admin管理员组文章数量:1327054
I'm trying to join two separate bezier curves into one continuous curve. Currently, what I have looks like this:
The problem is that they aren't joined, so the points at which they meet look pointy/sharp instead of curvy and smooth. I've looked into documentation for joining bezier curves in P5.js, but am unsure of how to translate this into HTML5 Canvas. How do I join these two bezier curves so that they look like one smooth and continuous curve?
This is my code:
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;
}
I'm trying to join two separate bezier curves into one continuous curve. Currently, what I have looks like this:
The problem is that they aren't joined, so the points at which they meet look pointy/sharp instead of curvy and smooth. I've looked into documentation for joining bezier curves in P5.js, but am unsure of how to translate this into HTML5 Canvas. How do I join these two bezier curves so that they look like one smooth and continuous curve?
This is my code:
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;
}
Share
Improve this question
asked Oct 1, 2020 at 3:49
Anokhee JandhyalaAnokhee Jandhyala
1931 silver badge7 bronze badges
2
- 1 not the simplest but still, html5tutorial./… – john-jones Commented Jul 21, 2021 at 10:26
- if you can calculate the lines angle at the end of each bezier curve. you can continue in that same direction for a little bit in the beginning of the next bezier. – john-jones Commented Jul 21, 2021 at 11:00
2 Answers
Reset to default 5Common tangent
To join two beziers smoothly you need to make the lines from the mon point parallel thus defining the tangent at the end and start of the two beziers to be the same.
The following image illustrates this
The line that is defined by the two control points (C2, C1) and the mon point (P) is the tangent of the curve at P. The length of the line segments have no constraints.
How?
There are dozens of ways to do this and how you do it is dependent on the requirements of the curve, the type of curve, and much more.
Example
I am not going to give a full example as it requires an understanding of vector maths and a cover all solution on the assumption you are not familiar with vector maths would be huge.
Thus the most basic pseudo code example uses the previous control and end points to calculate the next control point. ?
represents unknowns which are not bound by constraints required to keep the lines parallel
// 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 mon point P
ctx.bezierCurveTo(?,?, C2.x, C2.y, P.x, P.y)
ctx.bezierCurveTo(C1.x, C1.y, ?, ?, ?, ?)
In the below page:
https://www.w3schools./tags/tryit.asp?filename=tryhtml5_canvas_beziercurveto
You change the width and height of the canvas to 1000.
Then you replace the two lines between beginpath and stroke with the below code.
points=[
{x:0, y:300},//0
{x:100,y:500},//1
{x:200,y:300},//2
{x:300,y:100},//3
{x:400,y:300},//4
{x:100,y:500},//5
{x:100,y:300},//6
];
ctx.rect(points[0].x-5, points[0].y-5, 10,10);
var smoother={};
smoother.x=((points[1].x-points[0].x)/10)+points[0].x;
smoother.y=((points[1].y-points[0].y)/10)+points[0].y;
ctx.rect(smoother.x-5, smoother.y-5, 10,10);
ctx.rect(points[1].x-5, points[1].y-5, 10,10);
ctx.rect(points[2].x-5, points[2].y-5, 10,10);
ctx.moveTo(points[0].x,points[0].y);
ctx.bezierCurveTo(
smoother.x, smoother.y,
points[1].x, points[1].y,
points[2].x, points[2].y
);
var smoother={};
var dx=(points[2].x-points[1].x);
var dy=(points[2].y-points[1].y);
var yperx=(dy/dx);
travel_x=dx;
travel_y=(dx*yperx);
smoother.x=points[2].x+travel_x/3;
smoother.y=points[2].y+travel_y/3;
ctx.rect(smoother.x-5, smoother.y-5, 10,10);
ctx.rect(points[3].x-5, points[3].y-5, 10,10);
ctx.rect(points[4].x-5, points[4].y-5, 10,10);
ctx.moveTo(points[2].x,points[2].y);
ctx.bezierCurveTo(
smoother.x, smoother.y,
points[3].x, points[3].y,
points[4].x, points[4].y
);
var smoother={};
var dx=(points[4].x-points[3].x);
var dy=(points[4].y-points[3].y);
var yperx=(dy/dx);
travel_x=dx;
travel_y=(dx*yperx);
smoother.x=points[4].x+travel_x/3;
smoother.y=points[4].y+travel_y/3;
ctx.rect(smoother.x-5, smoother.y-5, 10,10);
ctx.rect(points[5].x-5, points[5].y-5, 10,10);
ctx.rect(points[6].x-5, points[6].y-5, 10,10);
ctx.moveTo(points[4].x,points[4].y);
ctx.bezierCurveTo(
smoother.x, smoother.y,
points[5].x, points[5].y,
points[6].x, points[6].y
);
You can also run it here by pressing the run button:
https://www.w3schools./code/tryit.asp?filename=GSP1RKBFHGGK
At that you can manipulate the pixels in points[], and notice that the bezier curves always connect kinda smoothly.
That's because in each new bezier curve, the system automatically makes the first bezier point, which only serves the role of smoothing the line. Which is basically just a point that continues in whatever direction the previous bezier was heading, for a little bit. The next pixel in the bezier is then an actual destination, which the given bezier curve then takes care of smoothing.
There is the number 3 in there, it represents how quickly you want to start going in the actual direction. If it's too large we start to too quickly head in the needed direction and the smoothness suffers. If it's too small we are ignoring too much where the line needs to be going, in favor of smoothness.
本文标签: javascriptHow to join 2 Bezier curves smoothly amp continuously with HTML5 CanvasStack Overflow
版权声明:本文标题:javascript - How to join 2 Bezier curves smoothly & continuously with HTML5 Canvas - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742214382a2434299.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论