Files
茂之钳 980cb32468
CI / Build & Test (push) Failing after 31s
CI / Release Build (push) Failing after 31s
fix: remove remaining /* ... */ inside doxygen blocks
2026-07-24 11:14:27 +00:00

163 lines
4.5 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include "vde/core/point.h"
#include "vde/core/aabb.h"
#include <vector>
#include <array>
namespace vde::core {
/**
* @brief 二维平面多边形
*
* 支持面积计算、点包含测试、简化和三角剖分。
* 顶点按顺序排列(闭合多边形),不存储首尾重复顶点。
*
* @note 内部假设简单多边形(无自交),非简单多边形的行为未定义
* @note 所有几何计算基于(假设的)XY 平面
*
* @ingroup core
*/
class Polygon2D {
public:
/// 构造空多边形
Polygon2D() = default;
/**
* @brief 从顶点列表构造多边形
*
* @param vertices 顶点序列(逆时针或顺时针均可)
*/
explicit Polygon2D(std::vector<Point2D> vertices) : vertices_(std::move(vertices)) {}
/// 获取顶点列表
[[nodiscard]] const std::vector<Point2D>& vertices() const { return vertices_; }
/// 获取顶点数量
[[nodiscard]] size_t size() const { return vertices_.size(); }
/// 多边形是否为空(< 3 个顶点视为退化)
[[nodiscard]] bool empty() const { return vertices_.empty(); }
/**
* @brief 有向面积(Shoelace 公式)
*
* 正值表示逆时针(CCW),负值表示顺时针(CW),零表示自交或退化。
*
* @return 有向面积
*
* @code{.cpp}
* Polygon2D poly({{0,0}, {1,0}, {0,1}});
* double sa = poly.signed_area(); // > 0 (CCW)
* @endcode
*/
[[nodiscard]] double signed_area() const;
/**
* @brief 绝对面积
* @return |signed_area()|
*/
[[nodiscard]] double area() const { return std::abs(signed_area()); }
/**
* @brief 周长(各边长之和)
* @return 总边长
*/
[[nodiscard]] double perimeter() const;
/**
* @brief 面积加权质心
*
* 使用多边形三角剖分的面积加权平均计算质心。
* 适用于非自交的任意多边形。
*
* @return 质心坐标
*/
[[nodiscard]] Point2D centroid() const;
/**
* @brief 二维轴对齐包围盒
*
* 返回 AABBz=0),min/max 的 z 分量均为 0。
*
* @return 包围盒
*/
[[nodiscard]] AABB<double> bounding_box() const;
/**
* @brief 点包含测试(射线法)
*
* 从测试点向右发射水平射线,计算与多边形边的交点数量。
* 奇数次交点在内部,偶数次在外部。
*
* @param p 测试点
* @return true 若点在多边形内部或边界上
*
* @note 边界上的点也返回 true
*/
[[nodiscard]] bool contains(const Point2D& p) const;
/**
* @brief 多边形是否为逆时针方向
* @return signed_area() > 0
*/
[[nodiscard]] bool is_ccw() const { return signed_area() > 0; }
/**
* @brief Douglas-Peucker 简化
*
* 用递归的 Douglas-Peucker 算法减少顶点数量,
* 保证简化后多边形与原多边形的最大偏差不超过 tolerance。
*
* @param tolerance 允许的最大偏差
* @return 简化后的新多边形
*
* @code{.cpp}
* // 将 1000 个顶点的多边形简化为约 100 个
* auto simple = poly.simplify(0.01);
* @endcode
*
* @see triangulate
*/
[[nodiscard]] Polygon2D simplify(double tolerance) const;
/**
* @brief 耳切法三角剖分(Ear Clipping
*
* 将简单多边形剖分为三角形,返回每个三角形的顶点索引三元组。
*
* @return 三角形列表,每个元素为 {i, j, k} 表示顶点索引
*
* @pre 多边形为简单多边形(无自交)
* @pre 顶点为逆时针顺序(CCW)
*
* @note 时间复杂度 O(n²),适用于顶点数 < 1000 的多边形
*
* @code{.cpp}
* Polygon2D poly(CCW vertices);
* auto tris = poly.triangulate();
* for (auto& t : tris) {
* // 顶点: poly.vertices()[t[0]], t[1], t[2]
* }
* @endcode
*
* @see simplify
*/
[[nodiscard]] std::vector<std::array<int, 3>> triangulate() const;
/**
* @brief Andrew's Monotone Chain 二维凸包
*
* 计算点集的凸包,返回逆时针排列的凸包多边形。
* 时间复杂度 O(n log n)。
*
* @param points 输入点集
* @return 凸包多边形(CCW,不含共线中间点)
*
* @see convex_hull_2d
*/
static Polygon2D convex_hull_2d(const std::vector<Point2D>& points);
private:
std::vector<Point2D> vertices_;
};
} // namespace vde::core