如何设置贝塞尔曲线的控制点来弯曲一条线?
How to set control points of a bezier curve to bend a line?
我想用贝塞尔曲线画一条稍微弯曲的线。
这是贝塞尔曲线函数:
function bezierCurve(controlPoint1, controlPoint2, line) { }
我不知道如何设置控制点来实现任何一条线的微弯线。
我试图找到这条线的垂直点:
function Line(a, b) {
let mid = [(a[0] + b[0]) / 2,
(a[1] + b[1]) / 2];
let dX = b[0] - a[0],
dY = b[1] - a[1];
this.perpPoint = (y) => {
let x1 = mid[0],
y1 = mid[1],
x;
if (dX === 0 || dY === 0) {
x = y;
y = y1;
return [x, y];
}
let m = dX / dY;
let perpendicularM = - 1 / m;
// y - y1 = m(x - x1)
// x = (y - y1) / m + x1
x = (y - y1) / m + x1;
return [x, y];
};
并用它以某种方式找到线中点正上方的点作为控制点,但没有成功。
函数
function bezierCurve(controlPoint1, controlPoint2, line) { }
建议曲线是三次贝塞尔曲线(两个控制点)你给出的函数看起来只是在中间找到一个点并偏移一些固定量。您将需要更多地控制点与线的关系。
与直线的垂直偏移。
下面的函数会给你更多的控制权,让你指定你想要的点沿线的位置以及该点应该离线多远。
参数 along
和 dist
是一条线的一部分,例如 along = 0.5
是一半,而 dist = 0.2
是线长度的 1/5。 dist > 0
并且该点偏移到线的右侧 dist < 0
并且偏移量向左(Y 轴指向下方)
function pointFromLine(along, dist, p1, p2, res = {}) {
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
res.x = p1.x + dx * along - dy * dist;
res.y = p1.y + dy * along + dx * dist;
return res;
}
找到距中心1/5线长的中点
const p1 = {x: 10, y: 10};
const p2 = {x: 510, y: 310};
const offset = pointFromLine(0.5, 0.2, p1, p2);
为立方贝塞尔曲线找到两个控制点。
const p1 = {x: 10, y: 10};
const p2 = {x: 510, y: 310};
const cp1 = pointFromLine(0.333, 0.2, p1, p2); // 1/3rd dist from start
const cp2 = pointFromLine(1 - 0.333, 0.2, p1, p2); // equal dist (1/3rd) from end of line
使用示例
以下代码片段显示了用于为立方贝塞尔曲线创建对称曲线的函数。移动滑块控制沿线的距离和距离线的距离偏移
function pointFromLine(along, dist, p1, p2, res = {}) {
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
res.x = p1.x + dx * along - dy * dist;
res.y = p1.y + dy * along + dx * dist;
return res;
}
const p1 = {x: 40, y: 40};
const p2 = {x: 160, y: 160};
const cp1 ={x: 0, y: 0};
const cp2 ={x: 0, y: 0};
const ctx = canvas.getContext("2d");
update();
function drawPoint(p) {
ctx.beginPath();
ctx.arc(p.x, p.y, 4, 0, Math.PI * 2);
ctx.fill();
}
function drawLine(p1, p2) {
ctx.lineWidth = 1;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
function drawCubicBezier(p1, p2, cp1, cp2) {
ctx.lineWidth = 3;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y);
ctx.bezierCurveTo(cp1.x, cp1.y, cp2.x, cp2.y, p2.x, p2.y);
ctx.stroke();
drawLine(p1,cp1);
drawLine(p2,cp2);
drawPoint(p1);
drawPoint(p2);
drawPoint(cp1);
drawPoint(cp2);
}
alongIn.addEventListener("input", update);
distIn.addEventListener("input", update);
function update() {
const a = alongIn.value * 1;
const d = distIn.value * 1;
info.textContent = `Along: ${a.toFixed(2)} Offset: ${d.toFixed(2)}`
ctx.clearRect(0,0,200,200);
drawCubicBezier(
p1,
p2,
pointFromLine(a , d, p1, p2, cp1),
pointFromLine(1 - a, d, p1, p2, cp2)
);
}
canvas {
border: 1px solid black;
}
Dist along: <input id="alongIn" type="range" min="-1" max="2" step="0.01" value="0.3"/>
Dist out: <input id="distIn" type="range" min="-1" max="2" step="0.01" value="0.3"/>
<div id="info"> </div>
<canvas id="canvas" width="200" height="200" ></canvas>
我想用贝塞尔曲线画一条稍微弯曲的线。
这是贝塞尔曲线函数:
function bezierCurve(controlPoint1, controlPoint2, line) { }
我不知道如何设置控制点来实现任何一条线的微弯线。
我试图找到这条线的垂直点:
function Line(a, b) {
let mid = [(a[0] + b[0]) / 2,
(a[1] + b[1]) / 2];
let dX = b[0] - a[0],
dY = b[1] - a[1];
this.perpPoint = (y) => {
let x1 = mid[0],
y1 = mid[1],
x;
if (dX === 0 || dY === 0) {
x = y;
y = y1;
return [x, y];
}
let m = dX / dY;
let perpendicularM = - 1 / m;
// y - y1 = m(x - x1)
// x = (y - y1) / m + x1
x = (y - y1) / m + x1;
return [x, y];
};
并用它以某种方式找到线中点正上方的点作为控制点,但没有成功。
函数
function bezierCurve(controlPoint1, controlPoint2, line) { }
建议曲线是三次贝塞尔曲线(两个控制点)你给出的函数看起来只是在中间找到一个点并偏移一些固定量。您将需要更多地控制点与线的关系。
与直线的垂直偏移。
下面的函数会给你更多的控制权,让你指定你想要的点沿线的位置以及该点应该离线多远。
参数 along
和 dist
是一条线的一部分,例如 along = 0.5
是一半,而 dist = 0.2
是线长度的 1/5。 dist > 0
并且该点偏移到线的右侧 dist < 0
并且偏移量向左(Y 轴指向下方)
function pointFromLine(along, dist, p1, p2, res = {}) {
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
res.x = p1.x + dx * along - dy * dist;
res.y = p1.y + dy * along + dx * dist;
return res;
}
找到距中心1/5线长的中点
const p1 = {x: 10, y: 10};
const p2 = {x: 510, y: 310};
const offset = pointFromLine(0.5, 0.2, p1, p2);
为立方贝塞尔曲线找到两个控制点。
const p1 = {x: 10, y: 10};
const p2 = {x: 510, y: 310};
const cp1 = pointFromLine(0.333, 0.2, p1, p2); // 1/3rd dist from start
const cp2 = pointFromLine(1 - 0.333, 0.2, p1, p2); // equal dist (1/3rd) from end of line
使用示例
以下代码片段显示了用于为立方贝塞尔曲线创建对称曲线的函数。移动滑块控制沿线的距离和距离线的距离偏移
function pointFromLine(along, dist, p1, p2, res = {}) {
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
res.x = p1.x + dx * along - dy * dist;
res.y = p1.y + dy * along + dx * dist;
return res;
}
const p1 = {x: 40, y: 40};
const p2 = {x: 160, y: 160};
const cp1 ={x: 0, y: 0};
const cp2 ={x: 0, y: 0};
const ctx = canvas.getContext("2d");
update();
function drawPoint(p) {
ctx.beginPath();
ctx.arc(p.x, p.y, 4, 0, Math.PI * 2);
ctx.fill();
}
function drawLine(p1, p2) {
ctx.lineWidth = 1;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
function drawCubicBezier(p1, p2, cp1, cp2) {
ctx.lineWidth = 3;
ctx.beginPath();
ctx.lineTo(p1.x, p1.y);
ctx.bezierCurveTo(cp1.x, cp1.y, cp2.x, cp2.y, p2.x, p2.y);
ctx.stroke();
drawLine(p1,cp1);
drawLine(p2,cp2);
drawPoint(p1);
drawPoint(p2);
drawPoint(cp1);
drawPoint(cp2);
}
alongIn.addEventListener("input", update);
distIn.addEventListener("input", update);
function update() {
const a = alongIn.value * 1;
const d = distIn.value * 1;
info.textContent = `Along: ${a.toFixed(2)} Offset: ${d.toFixed(2)}`
ctx.clearRect(0,0,200,200);
drawCubicBezier(
p1,
p2,
pointFromLine(a , d, p1, p2, cp1),
pointFromLine(1 - a, d, p1, p2, cp2)
);
}
canvas {
border: 1px solid black;
}
Dist along: <input id="alongIn" type="range" min="-1" max="2" step="0.01" value="0.3"/>
Dist out: <input id="distIn" type="range" min="-1" max="2" step="0.01" value="0.3"/>
<div id="info"> </div>
<canvas id="canvas" width="200" height="200" ></canvas>