Reputation: 34185
I want to render bezier curves in C++, so I started implementing it myself. For now, it doesn't have to be very efficient. My code somehow produces a near result, but those curves aren't accurate. (dvec2
is a vector of two double values.)
list<dvec2> bezier(list<dvec2> const &points, int resolution)
{
list<dvec2> samples;
double step = 1.0 / resolution;
for (double time = 0.0; time <= 1.0; time += step) {
list<dvec2> sliders = points;
while (sliders.size() > 1)
sliders = slide(sliders, time);
samples.push_back(sliders.front());
}
return samples;
}
list<dvec2> slide(list<dvec2> const &points, double time)
{
list<dvec2> result;
auto current = points.begin();
dvec2 last = *current;
for (++current; current != points.end(); ++current)
result.push_back(last * time + *current * (1.0 - time));
return result;
}
Currently, I create n-1 points from a curve by interpolating the first with the second, the second with the third, and so on, based on time t. Then, I reduce this new set of points again by the same algorithm, until I'm left with one point that I can draw. I think the approach should work.
On rendered image, you can see the algorithms outcome on several rendered curves.
For example, in the bottom left of the image, the two opposing curves should by symmetrical I think. Mine are biased by the direction. Moreover, those fully enclosed curves should at least draw a point in the center for t=0.5. What is causing this?
Upvotes: 3
Views: 369
Reputation: 45675
Your approach should work. You made a little oversight: Within slide()
, you don't update last
in your loop.
Try:
for (++current; current != points.end(); ++current) {
result.push_back(last * time + *current * (1.0 - time));
last = *current; // <--
}
Note that a different interpretation of bezier curves can be given by taking the sum of these products:
(Source: wikipedia)
Some terminology is associated with these parametric curves. We have
where the polynomials
are known as Bernstein basis polynomials of degree n.
Here, you need (precomputed) binomial coefficients, and by using the std::pow
function you end up with a single loop instead of two nested ones (considering n to be limited by a constant in practice, to make precomputation possible).
Upvotes: 4