Divide the Bezier curve into two equal halves

I have Bezier curves between 2 points. I would like to cut all the curves into two equal halves. One of my ideas is that I can control the value of "t". I will draw 2 curves for t = [0,0.5] and t = [0,5,1], but I do not know how to do this. Below is my code. I will not mind any other idea or suggestion

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>D3 test</title> <script src="http://d3js.org/d3.v3.min.js"></script> <script> var Over = function(){ d3.select(this) .style("stroke-opacity", 0.25); } var Out = function(){ d3.select(this) .transition().duration(200) .style("stroke-opacity", 0); } function curve(n,x1,y1,x2,y2){ var xr = (x1+x2)/2, yr = (y1+y2)/2, euDist = Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2)), x3 = -y1+xr+yr, x4 = -y2+xr+yr, y3 = x1+yr-xr, y4 = x2+yr-xr, ctrl , curveDescription; svg.append('path') .attr("stroke", 'blue') .attr('fill','none') .style("stroke-opacity",0.25) .attr('d', 'M'+x3+','+y3+'L'+x4+','+y4) .attr('stroke-width',strokeWidth); for(var j=0;j<=n;j++){ ctrl = [(x4-x3)*j/n+x3 , (y4-y3)*j/n+y3] , curveDescription= 'M' +x1+',' +y1+ 'Q' +ctrl[0]+','+ctrl[1]+',' +x2+',' +y2; svg.append('path') .attr("stroke", 'blue') .attr('fill','none') .style("stroke-opacity",0.25) .attr('d', curveDescription) .attr('stroke-width',strokeWidth); svg.append('path') .attr("stroke", 'blue') .attr('fill','none') .style("stroke-opacity",0) .on("mouseover", Over) .on("mouseout", Out) .attr('d', curveDescription) .attr('stroke-width',strokeWidth*25); } } </script> </head> <body> <script> var w = 1268 , h = 680 , strokeWidth = 2; var svg = d3.select("body") .append("svg") .attr("width", w) .attr("height", h) curve(5, 100,100, 400,500); </script> </body> </html> 
+4
source share
3 answers

Dividing bezier into two curves is quite simple. Check out the De Castellau algorithm. https://en.wikipedia.org/wiki/De_Casteljau 's_algorithm

Update

De Castellau is easier than it looks. This WP article may be clearer for non-mothers. Therefore, I will explain more simply.

Imagine you have a bezier defined by points A, B, C, and D. Where A and D are endpoints and B and C are control points.

So, let's say you wanted to find the value of the curve at the point 't' along the curve (where t is in the range 0..1. You can do this in geometry:

  • Find the point E, which is located on 't' in a straight line AB.
  • Find the point F, which is located on 't' in a straight line BC.
  • Find the point G, which is located on 't' along the line CD.

  • Find the point H that is on 't' in a straight line EF.

  • Find the point J that is on 't' in a straight line FG.

  • Finally, find the point K that is on 't' along the line HJ.

K is also equal to the point, which is equal to 't' along the bezier. This is the De Castellau algorithm.

But it’s useful that this also gives us control points of two beziers that could have occurred if the curve had been split at K. Two bezier-free curves: A, E, H, K and K, J, G, D.

In your case, t = 0.5, so finding two curves is just a sequence of additions and divides by 2.

  E = (A+B)/2 F = (B+C)/2 G = (C+D)/2 H = (E+F)/2 J = (F+G)/2 K = (H+J)/2 

Obviously, each of these calculations must be performed for x and y.

Hope this helps.

+16
source

Here is the formula for splitting bezier into two curves.

 var w = 800, h = 560; var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); var pts = [{x:20, y:20}, {x:20, y:100}, {x:200, y:100}, {x:200, y:20}]; var t = 0.5; function lerp(a, b, t) { var s = 1 - t; return {x:ax*s + bx*t, y:ay*s + by*t}; } function splitcurve() { var p0 = pts[0], p1 = pts[1], p2 = pts[2], p3 = pts[3]; var p4 = lerp(p0, p1, t); var p5 = lerp(p1, p2, t); var p6 = lerp(p2, p3, t); var p7 = lerp(p4, p5, t); var p8 = lerp(p5, p6, t); var p9 = lerp(p7, p8, t); var firsthalf = [p0, p4, p7, p9]; var secondhalf = [p9, p8, p6, p3]; console.log(firsthalf); console.log(secondhalf); ctx.beginPath(); ctx.moveTo(20,20); ctx.lineWidth=5; ctx.bezierCurveTo(20,100,200,100,200,20); ctx.strokeStyle="black"; ctx.stroke(); ctx.beginPath(); ctx.moveTo(p0.x,p0.y); ctx.lineWidth=5; ctx.bezierCurveTo(p4.x,p4.y,p7.x,p7.y,p9.x,p9.y); ctx.strokeStyle="blue"; ctx.stroke(); ctx.beginPath(); ctx.moveTo(p9.x,p9.y); ctx.lineWidth=5; ctx.bezierCurveTo(p8.x,p8.y,p6.x,p6.y,p3.x,p3.y); ctx.strokeStyle="red"; ctx.stroke(); } splitcurve(); 
+5
source

The answer to this question given by Paul Lebo was very useful to me. I thought that others would benefit even more if there was a visual one to agree with this answer, which I provide below.

The following diagram illustrates the points described in Paul Lebo's answer. See This Answer for an explanation. The actual diagram shows a particular case of t = 0.5, but the general principles are the same for any value of t between 0 and 1. The heavy black lines show the "control lines" for the original curve, and the red lines show them for the first "semi-criterion".

enter image description here

+4
source

Source: https://habr.com/ru/post/1500888/


All Articles