HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppModerate

Bezier curves of grade n

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
gradebeziercurves

Problem

I made a function which creates Bezier curves of grade n. What do you think?

float interpolate(float n1, float n2, float prec)
{
    return n1 + ((n2-n1) * prec);
}

std::vector make_bezier(const std::vector& anchors, double accuracy=10000.0)
{
    if(anchors.size() end;
    end.push_back(anchors[0]);

    for(float i=0.f; i temp;
        for(unsigned int j=1; j1)
        {
            std::vector temp2;

            for(unsigned int j=1; j<temp.size(); ++j)
                temp2.push_back(Vector2f(interpolate(temp[j-1].x, temp[j].x, i),
                                         interpolate(temp[j-1].y, temp[j].y, i)));
            temp = temp2;
        }
        end.push_back(temp[0]);
    }

    return end;
}

Solution

Just a few comments:

std::vector make_bezier(const std::vector& anchors, double accuracy=10000.0)


You're using float for all your other floating point variables. Unless there's some really good reason to use double here (for accuracy) I'd consider changing it to a float as well.

std::vector end;
end.push_back(anchors[0]);

for(float i=0.f; i<1.f; i+=1.f/accuracy)


I'd write this a bit differently. As it stands, i can accumulate rounding errors from one iteration of the loop to the next. I'd prefer to do something like:

for (int j=0; j<accuracy; j++) {
    float i = 1.0f/j;
    // ...


This way, each value of i is computed independently, and rounding from one iteration doesn't affect its value in the next.

std::vector temp;
    for(unsigned int j=1; j<anchors.size(); ++j)
        temp.push_back(Vector2f(interpolate(anchors[j-1].x, anchors[j].x, i),
                                interpolate(anchors[j-1].y, anchors[j].y, i)));


Literally all your calls to interolate (at least in this code) happen in pairs. That being the case, I think I'd rewrite it a bit to take a couple of vector2fs as parameters, and return a vector2f containing the interpolation on both the x and y components of the inputs. It also uses i as a third input. My immediate reaction would be to define interpolate as a lambda that captured i, and took the other two parameters as inputs.

vector2f interpolate(vector2f in1, vector2f const &in2) { 
    in1.x = /* ... */;
    in1.y = /* ... */;
    return in1;
}


With that in place, the loop above can be reduced to a fairly simple application of std::transform, something like this:

std::transform(anchors.begin(), anchors.end(), 
                anchors.begin()+1, 
                std::back_inserter(temp));


Of course, pretty much the same would happen here:

for(unsigned int j=1; j<temp.size(); ++j)
            temp2.push_back(Vector2f(interpolate(temp[j-1].x, temp[j].x, i),
                                     interpolate(temp[j-1].y, temp[j].y, i)));


...as well.

Code Snippets

std::vector<Vector2f> make_bezier(const std::vector<Vector2f>& anchors, double accuracy=10000.0)
std::vector<Vector2f> end;
end.push_back(anchors[0]);

for(float i=0.f; i<1.f; i+=1.f/accuracy)
for (int j=0; j<accuracy; j++) {
    float i = 1.0f/j;
    // ...
std::vector<Vector2f> temp;
    for(unsigned int j=1; j<anchors.size(); ++j)
        temp.push_back(Vector2f(interpolate(anchors[j-1].x, anchors[j].x, i),
                                interpolate(anchors[j-1].y, anchors[j].y, i)));
vector2f interpolate(vector2f in1, vector2f const &in2) { 
    in1.x = /* ... */;
    in1.y = /* ... */;
    return in1;
}

Context

StackExchange Code Review Q#43215, answer score: 11

Revisions (0)

No revisions yet.