void BsplineCurveEvaluator::evaluateCurve(const vector<Point> &control_points, vector<Point> &evaluated_curve_points, const float &animation_length, const bool &wrap_control_points) const { evaluated_curve_points.clear(); vector<Point> cps_; if (wrap_control_points) { cps_.push_back(Point((control_points.end() - 2)->x - animation_length, (control_points.end() - 2)->y)); cps_.push_back(Point(control_points.back().x - animation_length, control_points.back().y)); cps_.insert(cps_.end(), control_points.begin(), control_points.end()); cps_.push_back(Point(control_points.front().x + animation_length, control_points.front().y)); cps_.push_back(Point((control_points.begin() + 1)->x + animation_length, (control_points.begin() + 1)->y)); } else { cps_.push_back(control_points.front()); cps_.push_back(control_points.front()); cps_.insert(cps_.end(), control_points.begin(), control_points.end()); cps_.push_back(control_points.back()); cps_.push_back(control_points.back()); } static const Mat4d m = Mat4d(1, 4, 1, 0, 0, 4, 2, 0, 0, 2, 4, 0, 0, 1, 4, 1) / 6.0; BezierCurveEvaluator bce; for (size_t cp = 0; cp + 3 < cps_.size(); ++cp) { const Vec4d bx_vec(cps_[cp].x, cps_[cp + 1].x, cps_[cp + 2].x, cps_[cp + 3].x); const Vec4d by_vec(cps_[cp].y, cps_[cp + 1].y, cps_[cp + 2].y, cps_[cp + 3].y); Vec4d vx_vec = m * bx_vec; Vec4d vy_vec = m * by_vec; vector<Point> vps; for (int i = 0; i < 4; ++i) { vps.push_back(Point(vx_vec[i], vy_vec[i])); } vector<Point> evaluated; bce.evaluateCurve(vps, evaluated, animation_length, false); // Remove the edge points evaluated_curve_points.insert(evaluated_curve_points.end(), evaluated.begin(), evaluated.end() - 2); } if (!wrap_control_points) { evaluated_curve_points.push_back(Point(0, control_points[0].y)); evaluated_curve_points.push_back(Point(animation_length, control_points.back().y)); } }
void BSplineCurveEvaluator::evaluateCurve( const std::vector<Point>& controlPoints, std::vector<Point>& evaluatedPoints, const float& animationLength, const bool& beWrap) const { evaluatedPoints.clear(); if (!beWrap) { evaluatedPoints.push_back(Point(0, controlPoints.front().y)); evaluatedPoints.push_back(Point(animationLength, controlPoints.back().y)); } // a hack to make the endpoints controllable vector<Point> controlPointsCopy; if (beWrap) { Point start_p1 = Point((controlPoints.end() - 2)->x - animationLength, (controlPoints.end() - 2)->y); Point start_p2 = Point((controlPoints.end() - 1)->x - animationLength, (controlPoints.end() - 1)->y); Point end_p1 = Point((controlPoints.begin())->x + animationLength, (controlPoints.begin())->y); Point end_p2 = Point((controlPoints.begin() + 1)->x + animationLength, (controlPoints.begin() + 1)->y); controlPointsCopy.push_back(start_p1); controlPointsCopy.push_back(start_p2); controlPointsCopy.insert(controlPointsCopy.end(), controlPoints.begin(), controlPoints.end()); controlPointsCopy.push_back(end_p1); controlPointsCopy.push_back(end_p2); } else { controlPointsCopy.push_back(controlPoints.front()); controlPointsCopy.push_back(controlPoints.front()); controlPointsCopy.insert(controlPointsCopy.end(), controlPoints.begin(), controlPoints.end()); controlPointsCopy.push_back(controlPoints.back()); controlPointsCopy.push_back(controlPoints.back()); } const Mat4d basis = Mat4d( 1, 4, 1, 0, 0, 4, 2, 0, 0, 2, 4, 0, 0, 1, 4, 1) / 6.0; BezierCurveEvaluator bezierCurveEvaluator; for (size_t cnt = 0; cnt + 3 < controlPointsCopy.size(); ++cnt) { Vec4d param_x(controlPointsCopy[cnt].x, controlPointsCopy[cnt + 1].x, controlPointsCopy[cnt + 2].x, controlPointsCopy[cnt + 3].x); Vec4d param_y(controlPointsCopy[cnt].y, controlPointsCopy[cnt + 1].y, controlPointsCopy[cnt + 2].y, controlPointsCopy[cnt + 3].y); param_x = basis * param_x; param_y = basis * param_y; vector<Point> param_control; for (int i = 0; i < 4; ++i) { param_control.push_back(Point(param_x[i], param_y[i])); } vector<Point> param_evaluated; bezierCurveEvaluator.evaluateCurve(param_control, param_evaluated, animationLength, false); evaluatedPoints.insert(evaluatedPoints.end(), param_evaluated.begin(), param_evaluated.end()-2); } }