定义Triangle类,用于多边形的三角耳切。
下面给出Triangle的声明。
class Triangle : public Geometry
{
private:
Point _vecs[3] = {Point()};
public:
Triangle() {};
Triangle(const Point &point0, const Point &point1, const Point &point2);
Triangle(const double x0, const double y0, const double x1, const double y1, const double x2, const double y2);
Triangle(const Triangle &triangle);
const Type type() const override;
const bool empty() const override;
const double length() const override;
void clear() override;
Triangle *clone() const override;
double area() const;
// 顶角度数(弧度制)
double angle(const size_t index) const;
void reorder_points(const bool cw = true);
// 判断点顺序是否为顺时针
bool is_cw() const;
Point &operator[](const size_t index);
const Point &operator[](const size_t index) const;
Triangle &operator=(const Triangle &triangle);
Triangle operator+(const Point &point) const;
Triangle operator-(const Point &point) const;
void operator+=(const Point &point);
void operator-=(const Point &point);
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;
// 内接圆圆心
Point inner_circle_center() const;
// 内接圆半径
double inner_circle_radius() const;
};
下面给出Triangle的实现。
Triangle::Triangle(const Point &point0, const Point &point1, const Point &point2)
{
_vecs[0] = point0;
_vecs[1] = point1;
_vecs[2] = point2;
}
Triangle::Triangle(const double x0, const double y0, const double x1, const double y1, const double x2, const double y2)
{
_vecs[0].x = x0;
_vecs[0].y = y0;
_vecs[1].x = x1;
_vecs[1].y = y1;
_vecs[2].x = x2;
_vecs[2].y = y2;
}
Triangle::Triangle(const Triangle &triangle)
{
_vecs[0] = triangle._vecs[0];
_vecs[1] = triangle._vecs[1];
_vecs[2] = triangle._vecs[2];
}
const Type Triangle::type() const
{
return Type::TRIANGLE;
}
const bool Triangle::empty() const
{
return _vecs[0] == _vecs[1] || _vecs[1] == _vecs[2] || _vecs[0] == _vecs[2];
}
const double Triangle::length() const
{
return Geo::distance(_vecs[0], _vecs[1]) + Geo::distance(_vecs[1], _vecs[2]) + Geo::distance(_vecs[0], _vecs[2]);
}
void Triangle::clear()
{
for (size_t i = 0; i < 3; ++i)
{
_vecs[i].clear();
}
}
Triangle *Triangle::clone() const
{
return new Triangle(*this);
}
double Triangle::area() const
{
if (empty())
{
return 0;
}
const double a = Geo::distance(_vecs[0], _vecs[1]);
const double b = Geo::distance(_vecs[1], _vecs[2]);
const double c = Geo::distance(_vecs[0], _vecs[2]);
const double p = (a + b + c) / 2;
return std::sqrt(p * (p - a) * (p - b) * (p- c));
}
double Triangle::angle(const size_t index) const
{
assert(0 <= index && index <= 2);
if (empty())
{
return 0;
}
const double len0 = Geo::distance(_vecs[1], _vecs[2]);
const double len1 = Geo::distance(_vecs[0], _vecs[2]);
const double len2 = Geo::distance(_vecs[0], _vecs[1]);
switch (index)
{
case 0:
return std::acos((len1 * len1 + len2 * len2 - len0 * len0) / (2 * len1 * len2));
case 1:
return std::acos((len0 * len0 + len2 * len2 - len1 * len1) / (2 * len0 * len2));
case 2:
return std::acos((len0 * len0 + len1 * len1 - len2 * len2) / (2 * len0 * len1));
default:
return 0;
}
}
void Triangle::reorder_points(const bool cw)
{
if (cw)
{
if (!is_cw())
{
std::swap(_vecs[1], _vecs[2]);
}
}
else
{
if (is_cw())
{
std::swap(_vecs[1], _vecs[2]);
}
}
}
bool Triangle::is_cw() const
{
return Geo::is_on_left(_vecs[2], _vecs[1], _vecs[0]);
}
Point &Triangle::operator[](const size_t index)
{
assert(0 <= index && index <= 2);
return _vecs[index];
}
const Point &Triangle::operator[](const size_t index) const
{
assert(0 <= index && index <= 2);
return _vecs[index];
}
Triangle &Triangle::operator=(const Triangle &triangle)
{
if (this != &triangle)
{
_vecs[0] = triangle._vecs[0];
_vecs[1] = triangle._vecs[1];
_vecs[2] = triangle._vecs[2];
}
return *this;
}
Triangle Triangle::operator+(const Point &point) const
{
Triangle triangle(*this);
triangle._vecs[0] += point;
triangle._vecs[1] += point;
triangle._vecs[2] += point;
return triangle;
}
Triangle Triangle::operator-(const Point &point) const
{
Triangle triangle(*this);
triangle._vecs[0] -= point;
triangle._vecs[1] -= point;
triangle._vecs[2] -= point;
return triangle;
}
void Triangle::operator+=(const Point &point)
{
_vecs[0] += point;
_vecs[1] += point;
_vecs[2] += point;
}
void Triangle::operator-=(const Point &point)
{
_vecs[0] -= point;
_vecs[1] -= point;
_vecs[2] -= point;
}
void Triangle::transform(const double a, const double b, const double c, const double d, const double e, const double f)
{
_vecs[0].transform(a, b, c, d, e, f);
_vecs[1].transform(a, b, c, d, e, f);
_vecs[2].transform(a, b, c, d, e, f);
}
void Triangle::transform(const double mat[6])
{
_vecs[0].transform(mat);
_vecs[1].transform(mat);
_vecs[2].transform(mat);
}
void Triangle::translate(const double tx, const double ty)
{
_vecs[0].translate(tx, ty);
_vecs[1].translate(tx, ty);
_vecs[2].translate(tx, ty);
}
void Triangle::rotate(const double x, const double y, const double rad) // 弧度制
{
_vecs[0].rotate(x, y, rad);
_vecs[1].rotate(x, y, rad);
_vecs[2].rotate(x, y, rad);
}
void Triangle::scale(const double x, const double y, const double k)
{
_vecs[0].scale(x, y, k);
_vecs[1].scale(x, y, k);
_vecs[2].scale(x, y, k);
}
Polygon Triangle::convex_hull() const
{
if (empty())
{
return Polygon();
}
else
{
return Polygon({_vecs[0], _vecs[1], _vecs[2], _vecs[0]});
}
}
AABBRect Triangle::bounding_rect() const
{
if (empty())
{
return AABBRect();
}
const double left = std::min(_vecs[0].x, std::min(_vecs[1].x, _vecs[2].x));
const double right = std::max(_vecs[0].x, std::max(_vecs[1].x, _vecs[2].x));
const double top = std::max(_vecs[0].y, std::max(_vecs[1].y, _vecs[2].y));
const double bottom = std::min(_vecs[0].y, std::min(_vecs[1].y, _vecs[2].y));
return AABBRect(left, top, right, bottom);
}
Polygon Triangle::mini_bounding_rect() const
{
if (empty())
{
return Polygon();
}
double cs, area = DBL_MAX;
AABBRect rect, temp;
for (size_t i = 0; i < 3; ++i)
{
Triangle triangle(*this);
cs = (triangle[i].x * triangle[i < 2 ? i + 1 : 0].y - triangle[i < 2 ? i + 1 : 0].x * triangle[i].y)
/ (triangle[i < 2 ? i + 1 : 0].length() * triangle[i].length());
triangle.rotate(triangle[i].x, triangle[i].y, std::acos(cs));
temp = triangle.bounding_rect();
if (temp.area() < area)
{
rect = temp;
area = temp.area();
rect.rotate(triangle[i].x, triangle[i].y, -std::acos(cs));
}
}
return rect;
}
Point Triangle::inner_circle_center() const
{
const double a = Geo::distance(_vecs[1], _vecs[2]);
const double b = Geo::distance(_vecs[0], _vecs[2]);
const double c = Geo::distance(_vecs[0], _vecs[1]);
return (_vecs[0] * a + _vecs[1] * b + _vecs[2] * c) / (a + b + c);
}
double Triangle::inner_circle_radius() const
{
const double a = Geo::distance(_vecs[1], _vecs[2]);
const double b = Geo::distance(_vecs[0], _vecs[2]);
const double c = Geo::distance(_vecs[0], _vecs[1]);
const double p = (a + b + c) / 2;
return std::sqrt((p - a) * (p - b) * (p - c) / p);
}