Simplify a high order Bezier curve

I have an array of control points representing a Bezier curve. It can be a fifth-order Bezier curve or about 100, or something in between. I am looking for a way to simplify this Bezier curve into a few cubic Bezier curves. The figure below shows how a curve of the tenth power can be simplified to a three-dimensional curve, but I want to go further and simplify it to a few cubic Bezier curves to achieve a better approximation.

http://snag.gy/aHPjc.jpg

Sample code will be very helpful.

+5
source share
2 answers

As mohsenmadi has already pointed out: in general, this is not something you can do without coming up with your own error indicator. Another idea is to “well allow you to approximate this curve as a sequence of lower order curves”, so that we get something that looks better and does not actually require error rates. This is a bit like “smoothing” a curve on a line, but instead of lines we will use cubic Bezier segments, which gives attractive curves, while preserving all the “acceptable” for modern graphics libraries.

Then what we can do is this: divide this “100th order curve” into a sequence of Bezier cubic, selectively using the curve at regular intervals, and then passing these points through the Catmull-Rom algorithm. The procedure is quite simple:

  • Select some regular intervals for t , for example 0, 0.2, 0.4, 0.6, 0.8 and 1, then
  • create a set of points tvalues.map (t => getCoordinate (curve, t)). Then,
  • build a virtual start and end point: by forming point 0 , starting from point 1 and moving backward along its tangent and forming a point n+1 , starting from n and following its tangent. We do this because:
  • build poly-Catmull-Rom, starting at virtual point 0 and ending at virtual point n+1 .

Do it in the pictures. Let's start with the 11th order Bezier curve:

enter image description here

And then just let it check at regular intervals:

enter image description here

We come up with the 0th and n + 1st points:

enter image description here

And then we run the Catmull-Rom procedure:

 i = 0 e = points.length-4 curves = [] do { crset = points.subset(i, 4) curves.push(formCRCurve(crset)) } while(i++<e) 

What does formCRCurve do? Good question:

 formCRCurve(points: p1, p2, p3, p4): d_start = vector(p2.x - p1.x, p2.y - p1.y) d_end = vector(p4.x - p3.x, p4.y - p3.y) return Curve(p2, d_start, d_end, p3) 

So, we see why we need these virtual points: given the four points, we can form a Kathmull-Rum curve from points 2 to 3, using the tangent information that we get with a little help from points 1 and 4.

Of course, we really want Bezier curves, not Catmull-Roma curves, but since they are the same “view” of the curve, we can freely convert between the two , therefore:

 i = 0 e = points.length-4 bcurves = [] do { pointset = points.subset(i, 4) bcurves.push(formBezierCurve(pointset)) } while(i++<e) formBezierCurve(points: p1, p2, p3, p4): return bezier( p2, p2 + (p3 - p1)/6 p3 - (p4 - p2)/6 p3 ) 

Thus, a Catmull-Rom curve based on points {p1, p2, p3, p4} passing through points p2 and p3 can be written as an equivalent Bezier curve that uses start / control1 / control2 / end coodinates p2 , p2 + (p3 - p1)/6 , p3 - (p4 - p2)/6 and p3 .

+4
source

Firstly, you should know that there are no approaching curves of a lower degree that would justify you! You must enter errors without exiting. Then the questions arise: how to approximate so that the original and resulting curves are visually similar?

Suppose your original curve has degree n. First, subdivide it. You can split the curve as many times as you like without making any mistakes. Here, the degree of each unit is still equal to n, but the geometric complexity and speed of curvature are significantly reduced. Secondly, you reduce the degree of each unit, which is now a simple form without high curvature, which will lead to approximation errors.

+1
source

All Articles