Curve evalBezier( const vector< Vec3f >& P, unsigned steps )
{
    // Check
    if( P.size() < 4 || P.size() % 3 != 1 )
    {
        cerr << "evalBezier must be called with 3n+1 control points." << endl;
        exit( 0 );
    }

    cerr << "\t>>> evalBezier has been called with the following input:" << endl;

    cerr << "\t>>> Control points (type vector< Vec3f >): "<< endl;
    for( unsigned i = 0; i < P.size(); ++i )
    {
        cerr << "\t>>> "; printTranspose(P[i]); cerr << endl;
    }

    cerr << "\t>>> Steps (type steps): " << steps << endl;

    // Return value: initialize with starting values.  Note the
    // initial normal of [0,1,0] will result in the
    // "counterclockwise" specification for 2D curves on the xy-plane.
    // I.e., the normal of the curve is facing left from the
    // direction of travel.  For 3D curves, the choice of direction is
    // kind of arbitrary. so this initial normal works too.
	vector< Vec3f >::const_iterator segmentStart = P.begin();
	vector< Vec3f >::const_iterator segmentEnd = P.size() > 4 ?
		P.begin() + 4 :
		P.end();

    Curve R
	(
		coreBezier
		(
			P[0], P[1], P[2], P[3],
            Vec3f( 0, 0, 1 ),
            steps
		)
	);

    // Build the rest of the curve
    for( unsigned i = 0; i < ( P.size() - 4 ) / 3; ++i )
    {
		Vec3f p0 = P[ 3 * i + 3 ];
		Vec3f p1 = P[ 3 * i + 4 ];
		Vec3f p2 = P[ 3 * i + 5 ];
		Vec3f p3 = P[ 3 * i + 6 ];
		
        vector< CurvePoint > Rnew
		(
            coreBezier
			(
                p0, p1, p2, p3,
                R.back().B, // init with previous computed binormal
				steps
			)
		);

        R.pop_back();
        R.insert( R.end(), Rnew.begin(), Rnew.end() );
    }

    // Finally, check for loop and patch ends
    if( approx( R.front().V, R.back().V ) &&
        approx( R.front().T, R.back().T ) &&
        !approx( R.front().N, R.back().N ) 
        )
    {
        Vec3f axis = R.front().N.cross(R.back().N);
        float angle = FW::acos( dot( R.front().N, R.back().N ) );
        float sign = ( dot( axis, R.front().T ) > 0 ) ? 1.f : -1.f;

        for( unsigned i = 0; i < R.size(); ++i )
        {
            float d = float( i ) / ( R.size() - 1 );
            Mat3f M = Mat3f::rotation( R[i].T, -sign * d * angle );

            R[i].N = M * R[i].N;
            R[i].B = M * R[i].B;
        }
    }

    return R;
    
}