1

I am developing a graphical editor application. It has a Bezier tool. I want to implement it similar to the bezier control in Paint.NET application, where two handles of the curve (in addition to the end points) are placed on the curve itself, by which the user can control the curvature. Placement of these handles on the curve, gives a better sense and feel to the graphist, as is shown in this figure:enter image description here

But my problem is that DrawBezier method in .NET, gets two control points that are not guaranteed to be always placed on the curve. Do you know how can I use the coordinates of these two on-curve handles to draw a Bezier?

Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
dghadagh
  • 103
  • 1
  • 15
  • If the *parameter values* (roughly equivalent to the distance along the curve) of these points are unknown, then you have 4 equations with 6 unknowns (in 2D), which is *under-determined* i.e. there are infinitely many Bezier curves that fit these 4 points. In Paint.NET these points probably correspond to *known* parameters e.g. `t=1/3` and `t=2/3`, in which case the problem is deterministic and the curve equation can be solved to obtain the control points. – meowgoesthedog Dec 28 '18 at 13:58
  • @meowgoesthedog Would you please specify those 6 equations? – dghadagh Dec 28 '18 at 14:42
  • 4 equations and 6 unknowns, not 6 equations. The unknowns are the XY components of the two on-curve handles (x 4) and their corresponding Bezier parameters (x 2). – meowgoesthedog Dec 28 '18 at 14:43
  • 1
    Okay, after some digging into OpenPDN (the open-source fork of Paint.NET), it seems that the curve in question is in-fact **not** a cubic Bezier, but an interpolated cubic spline. Their implementation draws the curve "manually" as a series of straight lines. Go to https://github.com/rivy/OpenPDN/ and search for `SplineInterpolator`. Paint.NET does use Bezier curves elsewhere, but they are drawn by direct calls to GDI+ which require control points, and nowhere are these control points being computed. – meowgoesthedog Dec 28 '18 at 15:06
  • @meowgoesthedog Thank you very much. I will give it a look. Thanks again. – dghadagh Dec 28 '18 at 15:29
  • 1
    You can handle your points as interpolation cubic curve (or catmul rom) ... using this [interpolation -> Bezier](https://stackoverflow.com/a/22582447/2521214) you simply convert the points into BEZIER control points. However you need to use parameter `t=<-1,+1>` or use 3 BEZIER patches instead (by mirroring the missing control points) ... however such conversion might not copy the curve exactly ... – Spektre Dec 29 '18 at 10:55
  • 1
    You can use standard polynomial curve fitting (see https://pomax.github.io/bezierinfo/#curvefitting for instance, yielding the pretty similar looking https://i.imgur.com/HOjp4lh.png) but you're always going to have *some* free parameters because you don't just "not know the control points", you _also_ don't know which time values those two on-curve points you do have belong to. – Mike 'Pomax' Kamermans Dec 29 '18 at 21:36

2 Answers2

1

We can use standard polynomial curve fitting to find a single cubic Bezier curve through any set of four points, but you're always going to be left with a free parameter problem: two of the points are going to be the start and end of the curve, so we know their time values are 0 and 1, but the two points are entirely free in terms of time value, and so you're going to have to come up with a reasonable assumption on what they should be before you can evaluate your curve fit.

See https://pomax.github.io/bezierinfo/#curvefitting for the maths if you want to implement this yourself, or find a library that does polynomial fitting (which means any half-decent statistics package), and then for timing values you have a few options:

  • Assume the points line up with t=0, t=1/3, t=2/3, and t=1. This is almost always a bad idea because points are rarely evenly spaced with respects to the cubic distribution.
  • Guess the t values based on linear distance, with the full length of the polyline p0-p1-p2-p3 set to 1, and the value at each point simply equal to the distance along the polyline, so t0=0, t1=dist(p0,p1), t2=dist(p0,p1)+dist(p1,2), t3=1.
  • Get fancier and pick an initial set of t values, then analyze the resulting Bezier and iteratively generate new curves, optimizing on some quality like curvature homogeneity, bounding box/hull area, aligning p1/p2 on minimum radius, etc.

Of these, obviously 2 is going to give "reasonable" results with the least amount of effort, but if you're writing a graphics application, "reasonable" depends on what your users need, not what is easy for you.

Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
0

The DrawCurve method of the Graphics class does the job. That is, instead of using Bezier curves, you should use Canonical Spline.

I found it in Charles Petzold's book (Programming Windows with C#):

"The Canonical Spline - The Graphic class includes a second type of spline called the canonical spline, meaning a standard or normal spline..."

dghadagh
  • 103
  • 1
  • 15