gpt4 book ai didi

javascript - 如何在 Canvas 上绘制经过三个点的曲线?

转载 作者:行者123 更新时间:2023-12-03 08:41:47 26 4
gpt4 key购买 nike

我要做的是改变圆的曲线。如果我单击圆圈中的一个点并将其拖动到另一点,则该圆的弧线应相应地延伸或收缩。我打算使用贝泽曲线,但不能保证新的贝泽曲线会通过拖动点。附件是鼠标拖动时显示新曲线的图像,我无法解决。谁能在这件事上帮助我?我期待您的回复canvas image

最佳答案

将圆拟合到点

也许这会有所帮助。

示例顶部的函数 fitCircleToPoints(x1, y1, x2, y2, x3, y3) 会将一个圆拟合为 3 个点。

它返回一个对象

{
x, y, // center of circle
radius, // radius of circle
CCW, // true if circle segment is counter clockwise
}

如果这 3 个点都在同一条线上,则没有可以拟合的圆(半径无穷大无效),因此函数返回未定义。

function fitCircleToPoints(x1, y1, x2, y2, x3, y3) {
var x, y, u;
const slopeA = (x2 - x1) / (y1 - y2); // slope of vector from point 1 to 2
const slopeB = (x3 - x2) / (y2 - y3); // slope of vector from point 2 to 3
if (slopeA === slopeB) { return } // Slopes are same thus 3 points form striaght line. No circle can fit.
if (y1 === y2) { // special case with points 1 and 2 have same y
x = ((x1 + x2) / 2);
y = slopeB * x + (((y2 + y3) / 2) - slopeB * ((x2 + x3) / 2));
} else if(y2 === y3) { // special case with points 2 and 3 have same y
x = ((x2 + x3) / 2);
y = slopeA * x + (((y1 + y2) / 2) - slopeA * ((x1 + x2) / 2));
} else {
x = ((((y2 + y3) / 2) - slopeB * ((x2 + x3) / 2)) - (u = ((y1 + y2) / 2) - slopeA * ((x1 + x2) / 2))) / (slopeA - slopeB);
y = slopeA * x + u;
}

return {
x, y,
radius: ((x1 - x) ** 2 + (y1 - y) ** 2) ** 0.5,
CCW: ((x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1)) >= 0,
};
}


requestAnimationFrame(update);

Math.TAU = Math.PI * 2;
const ctx = canvas.getContext("2d");
const mouse = {x : 0, y : 0, button : false}
function mouseEvents(e){
const bounds = canvas.getBoundingClientRect();
mouse.x = e.pageX - bounds.left - scrollX;
mouse.y = e.pageY - bounds.top - scrollY;
mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
}
["down","up","move"].forEach(name => document.addEventListener("mouse" + name, mouseEvents));
var w = canvas.width, h = canvas.height, cw = w / 2, ch = h / 2;
var nearest, ox, oy, dragging, dragIdx;
const points = [10,110,200,100,400,110];
function drawPoint(x, y, rad, col = "black") {
ctx.strokeStyle = col;
ctx.beginPath();
ctx.arc(x, y, rad, 0, Math.TAU);
ctx.stroke();
}
function drawLines(idx, col = "black") {
ctx.strokeStyle = col;
ctx.beginPath();
ctx.lineTo(points[idx++], points[idx++]);
ctx.lineTo(points[idx++], points[idx++]);
ctx.lineTo(points[idx++], points[idx++]);
ctx.stroke();
}
function drawPoints() {
var i = 0, x, y;
nearest = - 1;
var minDist = 20;
while (i < points.length) {
drawPoint(x = points[i++], y = points[i++], 4);
const dist = (x - mouse.x) ** 2 + (y - mouse.y) ** 2;
if (dist < minDist) {
minDist = dist;
nearest = i - 2;
}
}
}

function update(){
ctx.setTransform(1,0,0,1,0,0); // reset transform
if (w !== innerWidth || h !== innerHeight) {
cw = (w = canvas.width = innerWidth) / 2;
ch = (h = canvas.height = innerHeight) / 2;
} else {
ctx.clearRect(0,0,w,h);
}
canvas.style.cursor = "default";
drawPoints();
if (nearest > -1) {
if (mouse.button) {
if (!dragging) {
dragging = true;
ox = points[nearest] - mouse.x;
oy = points[nearest+1] - mouse.y;
dragIdx = nearest;
}
} else {
canvas.style.cursor = "move";
}
drawPoint(points[nearest], points[nearest + 1], 6, "red")
}
if (dragging) {
if (!mouse.button) {
dragging = false;
} else {
points[dragIdx] = mouse.x + ox;
points[dragIdx + 1] = mouse.y + oy
canvas.style.cursor = "none";
}
}

drawLines(0, "#0002");
const circle = fitCircleToPoints(points[0], points[1], points[2], points[3], points[4], points[5]);
if (circle) {
ctx.strokeStyle = "#000";
const ang1 = Math.atan2(points[1] - circle.y, points[0]- circle.x);
const ang2 = Math.atan2(points[5] - circle.y, points[4]- circle.x);
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.radius, ang1, ang2, circle.CCW);
ctx.stroke();
}
requestAnimationFrame(update);
}
canvas { position : absolute; top : 0px; left : 0px; }
<canvas id="canvas"></canvas>
Use mouse to move points.

关于javascript - 如何在 Canvas 上绘制经过三个点的曲线?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62550460/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com