定义Bezier类,这是为了能绘制曲线才定义的类。Bezier对象中有一个Polyline对象来表示贝塞尔曲线的形状,而Bezier本身的点则表示控制点。为了降低性能开销,仅在构造Bezier和修改Bezier控制点时重新计算贝塞尔曲线的形状,变换Bezier时,分别对Bezier本身的点和其中的Polyline的点做变换,而不重新计算形状。
下面给出Bezier的声明。
class Bezier : public Polyline
{
private:
size_t _order = 2;
Polyline _shape;
public:
Bezier(const size_t n);
Bezier(const Bezier &bezier);
Bezier(std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end, const size_t n);
Bezier(const std::initializer_list<Point> &points, const size_t n);
const Type type() const override;
// 贝塞尔曲线阶数
const size_t &order() const;
const Polyline &shape() const;
void update_shape(const double step = 0.01);
void append_shape(const double step = 0.01);
const double length() const override;
void clear() override;
Bezier *clone() const override;
Bezier &operator=(const Bezier &bezier);
void transform(const double a, const double b, const double c, const double d, const double e, const double f) override;
void transform(const double mat[6]) override;
void translate(const double tx, const double ty) override;
void rotate(const double x, const double y, const double rad) override;
void scale(const double x, const double y, const double k) override;
Polygon convex_hull() const override;
AABBRect bounding_rect() const override;
Polygon mini_bounding_rect() const override;
};
下面给出Bezier的实现。
Bezier::Bezier(const size_t n)
: _order(n)
{
_shape.shape_fixed = true;
}
Bezier::Bezier(const Bezier &bezier)
: Polyline(bezier), _order(bezier._order), _shape(bezier._shape)
{
_shape.shape_fixed = true;
}
Bezier::Bezier(std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end, const size_t n)
: Polyline(begin, end), _order(n)
{
_shape.shape_fixed = true;
update_shape();
}
Bezier::Bezier(const std::initializer_list<Point> &points, const size_t n)
: Polyline(points), _order(n)
{
_shape.shape_fixed = true;
update_shape();
}
const Type Bezier::type() const
{
return Type::BEZIER;
}
const size_t &Bezier::order() const
{
return _order;
}
const Polyline &Bezier::shape() const
{
return _shape;
}
void Bezier::update_shape(const double step)
{
assert(0 < step && step < 1);
_shape.clear();
std::vector<int> temp(1, 1), nums(_order + 1, 1);
for (size_t i = 1; i <= _order; ++i)
{
for (size_t j = 1; j < i; ++j)
{
nums[j] = temp[j - 1] + temp[j];
}
temp.assign(nums.begin(), nums.begin() + i + 1);
}
double t = 0;
Point point;
for (size_t i = 0, end = _points.size() - _order; i < end; i += _order)
{
_shape.append(_points[i]);
t = 0;
while (t <= 1)
{
point.clear();
for (size_t j = 0; j <= _order; ++j)
{
point += (_points[j + i] * (nums[j] * std::pow(1 - t, _order - j) * std::pow(t, j)));
}
_shape.append(point);
t += step;
}
}
_shape.append(_points.back());
}
void Bezier::append_shape(const double step)
{
assert(0 < step && step < 1);
if ((_points.size() - 1) % _order > 0)
{
return;
}
std::vector<int> temp(1, 1), nums(_order + 1, 1);
for (size_t i = 1; i <= _order; ++i)
{
for (size_t j = 1; j < i; ++j)
{
nums[j] = temp[j - 1] + temp[j];
}
temp.assign(nums.begin(), nums.begin() + i + 1);
}
double t = 0;
Point point;
const size_t i = _points.size() - _order - 1;
while (t <= 1)
{
point.clear();
for (size_t j = 0; j <= _order; ++j)
{
point += (_points[j + i] * (nums[j] * std::pow(1 - t, _order - j) * std::pow(t, j)));
}
_shape.append(point);
t += step;
}
_shape.append(_points.back());
}
const double Bezier::length() const
{
return _shape.length();
}
void Bezier::clear()
{
_shape.clear();
Polyline::clear();
}
Bezier *Bezier::clone() const
{
return new Bezier(*this);
}
Bezier &Bezier::operator=(const Bezier &bezier)
{
if (this != &bezier)
{
Polyline::operator=(bezier);
_shape = bezier._shape;
}
return *this;
}
void Bezier::transform(const double a, const double b, const double c, const double d, const double e, const double f)
{
Polyline::transform(a, b, c, d, e, f);
_shape.transform(a, b, c, d, e, f);
}
void Bezier::transform(const double mat[6])
{
Polyline::transform(mat);
_shape.transform(mat);
}
void Bezier::translate(const double tx, const double ty)
{
Polyline::translate(tx, ty);
_shape.translate(tx, ty);
}
void Bezier::rotate(const double x, const double y, const double rad)
{
Polyline::rotate(x, y, rad);
_shape.rotate(x, y, rad);
}
void Bezier::scale(const double x, const double y, const double k)
{
Polyline::scale(x, y, k);
_shape.scale(x, y, k);
}
Polygon Bezier::convex_hull() const
{
return _shape.convex_hull();
}
AABBRect Bezier::bounding_rect() const
{
return _shape.bounding_rect();
}
Polygon Bezier::mini_bounding_rect() const
{
return _shape.mini_bounding_rect();
}