定义Polyline类,作为多段线,这回是一个常用的几何对象。
下面给出Polyline的声明。
class Polyline : public Geometry
{
protected:
std::vector<Point> _points;
public:
Polyline() {};
Polyline(const Polyline &polyline);
Polyline(std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end);
Polyline(const std::initializer_list<Point> &points);
const Type type() const override;
const size_t size() const;
const bool empty() const override;
const double length() const override;
void clear() override;
Polyline *clone() const override;
Point &operator[](const size_t index);
const Point &operator[](const size_t index) const;
Polyline &operator=(const Polyline &polyline);
Polyline operator+(const Point &point) const;
Polyline operator-(const Point &point) const;
void operator+=(const Point &point);
void operator-=(const Point &point);
virtual void append(const Point &point);
virtual void append(const Polyline &polyline);
virtual void append(std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end);
virtual void insert(const size_t index, const Point &point);
virtual void insert(const size_t index, const Polyline &polyline);
virtual void insert(const size_t index, std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end);
virtual void remove(const size_t index);
virtual void remove(const size_t index, const size_t count);
virtual Point pop(const size_t index);
void flip();
Point &front();
const Point &front() const;
Point &back();
const Point &back() const;
std::vector<Point>::iterator begin();
std::vector<Point>::const_iterator begin() const;
std::vector<Point>::const_iterator cbegin() const;
std::vector<Point>::iterator end();
std::vector<Point>::const_iterator end() const;
std::vector<Point>::const_iterator cend() const;
std::vector<Point>::reverse_iterator rbegin();
std::vector<Point>::const_reverse_iterator rbegin() const;
std::vector<Point>::const_reverse_iterator crbegin() const;
std::vector<Point>::reverse_iterator rend();
std::vector<Point>::const_reverse_iterator rend() const;
std::vector<Point>::const_reverse_iterator crend() const;
std::vector<Point>::iterator find(const Point &point);
std::vector<Point>::const_iterator find(const Point &point) const;
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;
};
下面给出Polyline的实现。
Polyline::Polyline(const Polyline &polyline)
:Geometry(polyline)
,_points(polyline._points)
{}
Polyline::Polyline(std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end)
{
_points.push_back(*begin);
while (++begin != end)
{
if (*begin != _points.back())
{
_points.push_back(*begin);
}
}
}
Polyline::Polyline(const std::initializer_list<Point>& points)
{
_points.push_back(*points.begin());
for (const Point& point : points)
{
if (point != _points.back())
{
_points.push_back(point);
}
}
}
const Type Polyline::type() const
{
return Type::POLYLINE;
}
const size_t Polyline::size() const
{
return _points.size();
}
const bool Polyline::empty() const
{
return _points.empty();
}
const double Polyline::length() const
{
double reuslt = 0;
for (size_t i = 1, count = _points.size(); i < count; ++i)
{
reuslt += Geo::distance(_points[i], _points[i-1]);
}
return reuslt;
}
void Polyline::clear()
{
_points.clear();
}
Polyline *Polyline::clone() const
{
return new Polyline(*this);
}
Point &Polyline::operator[](const size_t index)
{
assert(index < _points.size());
return _points[index];
}
const Point &Polyline::operator[](const size_t index) const
{
assert(index < _points.size());
return _points[index];
}
Polyline &Polyline::operator=(const Polyline &polyline)
{
if (this != &polyline)
{
Geometry::operator=(polyline);
_points = polyline._points;
}
return *this;
}
Polyline Polyline::operator+(const Point &point) const
{
std::vector<Point> temp(_points);
for (Point &p : temp)
{
p += point;
}
return Polyline(temp.begin(), temp.end());
}
Polyline Polyline::operator-(const Point &point) const
{
std::vector<Point> temp(_points);
for (Point &p : temp)
{
p -= point;
}
return Polyline(temp.begin(), temp.end());
}
void Polyline::operator+=(const Point &point)
{
for (Point &p : _points)
{
p += point;
}
}
void Polyline::operator-=(const Point &point)
{
for (Point &p : _points)
{
p -= point;
}
}
void Polyline::append(const Point &point)
{
if (_points.empty() || _points.back() != point)
{
_points.push_back(point);
}
}
void Polyline::append(const Polyline &polyline)
{
if (_points.empty() || _points.back() != polyline._points.front())
{
_points.insert(_points.cend(), polyline._points.cbegin(), polyline._points.cend());
}
else
{
_points.insert(_points.cend(), polyline._points.cbegin() + 1, polyline._points.cend());
}
}
void Polyline::append(std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end)
{
if (_points.empty() || _points.back() != *begin)
{
_points.insert(_points.end(), begin, end);
}
else
{
_points.insert(_points.end(), begin + 1, end);
}
}
void Polyline::insert(const size_t index, const Point &point)
{
assert(index < _points.size());
if (_points[index] == point || (index > 0 && _points[index - 1] == point))
{
return;
}
else
{
_points.insert(_points.cbegin() + index, point);
}
}
void Polyline::insert(const size_t index, const Polyline& polyline)
{
assert(index < _points.size());
if (polyline.empty())
{
return;
}
int i = (index > 0 && _points[index - 1] == polyline._points.front()), j = _points[index] == polyline._points.back();
_points.insert(_points.cbegin() + index, polyline._points.cbegin() + i, polyline._points.cend() - j);
}
void Polyline::insert(const size_t index, std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end)
{
assert(index < _points.size());
int i = (index > 0 && _points[index] == *begin);
_points.insert(_points.end(), begin + i, end);
const size_t len = std::distance(begin, end);
if (_points[index + len] == _points[index + len + 1])
{
_points.erase(_points.begin() + index + len + 1);
}
}
void Polyline::remove(const size_t index)
{
assert(index < _points.size());
_points.erase(_points.begin() + index);
}
void Polyline::remove(const size_t index, const size_t count)
{
assert(index < _points.size());
_points.erase(_points.begin() + index, _points.begin() + index + count);
}
Point Polyline::pop(const size_t index)
{
assert(index < _points.size());
Point point(std::move(_points[index]));
_points.erase(_points.begin() + index);
return point;
}
void Polyline::flip()
{
std::reverse(_points.begin(), _points.end());
}
Point &Polyline::front()
{
assert(!_points.empty());
return _points.front();
}
const Point &Polyline::front() const
{
assert(!_points.empty());
return _points.front();
}
Point &Polyline::back()
{
assert(!_points.empty());
return _points.back();
}
const Point &Polyline::back() const
{
assert(!_points.empty());
return _points.back();
}
std::vector<Point>::iterator Polyline::begin()
{
return _points.begin();
}
std::vector<Point>::const_iterator Polyline::begin() const
{
return _points.begin();
}
std::vector<Point>::const_iterator Polyline::cbegin() const
{
return _points.cbegin();
}
std::vector<Point>::iterator Polyline::end()
{
return _points.end();
}
std::vector<Point>::const_iterator Polyline::end() const
{
return _points.end();
}
std::vector<Point>::const_iterator Polyline::cend() const
{
return _points.cend();
}
std::vector<Point>::reverse_iterator Polyline::rbegin()
{
return _points.rbegin();
}
std::vector<Point>::const_reverse_iterator Polyline::rbegin() const
{
return _points.rbegin();
}
std::vector<Point>::const_reverse_iterator Polyline::crbegin() const
{
return _points.crbegin();
}
std::vector<Point>::reverse_iterator Polyline::rend()
{
return _points.rend();
}
std::vector<Point>::const_reverse_iterator Polyline::rend() const
{
return _points.rend();
}
std::vector<Point>::const_reverse_iterator Polyline::crend() const
{
return _points.crend();
}
std::vector<Point>::iterator Polyline::find(const Point &point)
{
return std::find(_points.begin(), _points.end(), point);
}
std::vector<Point>::const_iterator Polyline::find(const Point &point) const
{
return std::find(_points.cbegin(), _points.cend(), point);
}
void Polyline::transform(const double a, const double b, const double c, const double d, const double e, const double f)
{
std::for_each(_points.begin(), _points.end(), [=](Point &point){point.transform(a,b,c,d,e,f);});
}
void Polyline::transform(const double mat[6])
{
std::for_each(_points.begin(), _points.end(), [=](Point &point){point.transform(mat);});
}
void Polyline::translate(const double tx, const double ty)
{
std::for_each(_points.begin(), _points.end(), [=](Point &point){point.translate(tx, ty);});
}
void Polyline::rotate(const double x, const double y, const double rad)
{
std::for_each(_points.begin(), _points.end(), [=](Point &point){point.rotate(x, y, rad);});
}
void Polyline::scale(const double x, const double y, const double k)
{
std::for_each(_points.begin(), _points.end(), [=](Point &point){point.scale(x, y, k);});
}
Polygon Polyline::convex_hull() const
{
std::vector<Point> points(_points);
std::sort(points.begin(), points.end(), [](const Point &a, const Point &b)
{return a.y < b.y;});
const Point origin(points.front());
std::for_each(points.begin(), points.end(), [=](Point &p){p -= origin;});
std::sort(points.begin() + 1, points.end(), [](const Point &a, const Point &b)
{
if (a.x / a.length() != b.x / b.length())
{
return a.x / a.length() > b.x / b.length();
}
else
{
return a.length() < b.length();
}
});
std::for_each(points.begin(), points.end(), [=](Point &p){p += origin;});
std::vector<Point> hull(points.begin(), points.begin() + 2);
size_t count = hull.size(), index = 0;
Geo::Vector vec0, vec1;
std::vector<bool> used(points.size(), false);
for (size_t i = 2, end = points.size(); i < end; ++i)
{
vec0 = hull.back() - hull[count - 2];
vec1 = vec0 + points[i] - hull.back();
while (count >= 2 && vec0.x * vec1.y - vec1.x * vec0.y < 0)
{
hull.pop_back();
--count;
vec0 = hull.back() - hull[count - 2];
vec1 = vec0 + points[i] - hull.back();
}
++count;
hull.emplace_back(points[i]);
used[i] = true;
}
for (size_t i = 1; count < 2; ++i)
{
if (used[i])
{
continue;
}
hull.emplace_back(points[points.size() - i]);
++count;
used[points.size() - i] = true;
}
for (size_t i = points.size() - 1; i > 0; --i)
{
if (used[i])
{
continue;
}
vec0 = hull.back() - hull[count - 2];
vec1 = vec0 + points[i] - hull.back();
while (count >= 2 && vec0.x * vec1.y - vec1.x * vec0.y < 0)
{
hull.pop_back();
--count;
vec0 = hull.back() - hull[count - 2];
vec1 = vec0 + points[i] - hull.back();
}
++count;
hull.emplace_back(points[i]);
}
vec0 = hull.back() - hull[count - 2];
vec1 = vec0 + points.front() - hull.back();
if (count >= 2 && vec0.x * vec1.y - vec0.y * vec1.x < 0)
{
hull.pop_back();
}
hull.emplace_back(points.front());
return Polygon(hull.cbegin(), hull.cend());
}
AABBRect Polyline::bounding_rect() const
{
if (_points.empty())
{
return AABBRect();
}
double x0 = DBL_MAX, y0 = DBL_MAX, x1 = (-FLT_MAX), y1 = (-FLT_MAX);
for (const Point &point : _points)
{
x0 = std::min(x0, point.x);
y0 = std::min(y0, point.y);
x1 = std::max(x1, point.x);
y1 = std::max(y1, point.y);
}
return AABBRect(x0, y1, x1, y0);
}
Polygon Polyline::mini_bounding_rect() const
{
if (_points.empty())
{
return Polygon();
}
double cs, area = DBL_MAX;
AABBRect rect, temp;
const Polygon hull(convex_hull());
for (size_t i = 1, count = hull.size(); i < count; ++i)
{
Polygon polygon(hull);
cs = (polygon[i - 1].x * polygon[i].y - polygon[i].x * polygon[i - 1].y)
/ (polygon[i].length() * polygon[i - 1].length());
polygon.rotate(polygon[i - 1].x, polygon[i - 1].y, std::acos(cs));
temp = polygon.bounding_rect();
if (temp.area() < area)
{
rect = temp;
area = temp.area();
rect.rotate(polygon[i - 1].x, polygon[i - 1].y, -std::acos(cs));
}
}
return rect;
}