Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw a quadratic Bézier curve through three given points

I have three points in 2D and I want to draw a quadratic Bézier curve passing through them. How do I calculate the middle control point (x1 and y1 as in quadTo)? I know linear algebra from college but need some simple help on this.

How can I calculate the middle control point so that the curve passes through it as well?

like image 478
Alex Avatar asked Jul 15 '11 18:07

Alex


People also ask

What is quadratic Bezier curve?

Quadratic Bezier curve is a point-to-point linear interpolation of two Linear Bezier Curves. For given three points P0, P1 and P2, a quadratic bezier curve is a linear interpolation of two points, got from Linear Bezier curve of P0 and P1 and Linear Bezier Curve of P1 and P2.

How do you draw a Bezier curve?

To draw a line using this equation, one can divide the curve into smaller segments, calculate the end points of each segment using the Bezier cubic equation and draw the line for the segment. For instance, one can draw a line between the points defined by t = 0 and t = 0.01, then t = 0.01 and t = 0.02, and so on.

What is the difference between a cubic Bezier curve and a quadratic Bezier curve?

A cubic Bezier curve has 2 control points, whereas the quadratic Bezier curve only has 1 control point. Cubic Bezier curves - 3 rd degree curves - to fully define such a curve, one will need to specify 4 points: two anchor points (P1 and P2) - the curve starts and, respectively, ends in these points.

How do you calculate the control point on a Bezier curve?

Any series of 4 distinct points can be converted to a cubic Bézier curve that goes through all 4 points in order. Given the starting and ending point of some cubic Bézier curve, and the points along the curve corresponding to t = 1/3 and t = 2/3, the control points for the original Bézier curve can be recovered.


2 Answers

Let P0, P1, P2 be the control points, and Pc be your fixed point you want the curve to pass through.

Then the Bezier curve is defined by

P(t) = P0*t^2 + P1*2*t*(1-t) + P2*(1-t)^2 

...where t goes from zero to 1.

There are an infinite number of answers to your question, since it might pass through your point for any value of t... So just pick one, like t=0.5, and solve for P1:

Pc = P0*.25 + P1*2*.25 + P2*.25  P1 = (Pc - P0*.25 - P2*.25)/.5     = 2*Pc - P0/2 - P2/2 

There the "P" values are (x,y) pairs, so just apply the equation once for x and once for y:

x1 = 2*xc - x0/2 - x2/2 y1 = 2*yc - y0/2 - y2/2 

...where (xc,yc) is the point you want it to pass through, (x0,y0) is the start point, and (x2,y2) is the end point. This will give you a Bezier that passes through (xc,yc) at t=0.5.

like image 71
Nemo Avatar answered Sep 18 '22 12:09

Nemo


I have used Nemos answer in my JavaFX apllication, but my goal was to draw the curve, so that the visual turning point of the curve always fits with the choosen fixed one (CP).

CP = ControlPoint
SP = StartPoint
EP = EndPoint
BP(t) = variable Point on BeziérCurve where t is between 0 and 1

To achieve this i made a variable t (not fix 0.5). If the choosen Point CP is no longer in the middle between SP and EP, you have to vary t up or down a little bit. As a first step you need to know if CP is closer to SP or EP: Let distanceSP be the distance between CP and SP and distanceEP the distance between CP and EP then i define ratio as:

ratio = (distanceSP - distanceEP) / (distanceSP + distanceEP); 

Now we are going to use this to vary t up and down:

ratio = 0.5 - (1/3) * ratio; 

note: This is still an approximation and 1/3 is choosen by try and error.

Here is my Java-Function: (Point2D is a class of JavaFX)

private Point2D adjustControlPoint(Point2D start, Point2D end, Point2D visualControlPoint) {     // CP = ControlPoint, SP = StartPoint, EP = EndPoint, BP(t) = variable Point on BeziérCurve where t is between 0 and 1     // BP(t) = SP*t^2 + CP*2*t*(1-t) + EP*(1-t)^2     // CP = (BP(t) - SP*t^2 - EP*(1-t)^2) / ( 2*t*(1-t) )     // but we are missing t the goal is to approximate t     double distanceStart  = visualControlPoint.distance(start);     double distanceEnd    = visualControlPoint.distance(end);     double ratio          = (distanceStart - distanceEnd) / (distanceStart + distanceEnd);     // now approximate ratio to be t     ratio = 0.5 - (1.0 / 3) * ratio;      double ratioInv = 1 - ratio;     Point2D term2 = start.multiply( ratio * ratio );     Point2D term3 = end.multiply( ratioInv * ratioInv );     double  term4 = 2 * ratio * ratioInv;      return visualControlPoint.subtract(term2).subtract(term3).multiply( 1 / term4); } 

I hope this helps.

like image 21
Zomono Avatar answered Sep 18 '22 12:09

Zomono