用鞋带公式计算std::vector存储的多边形面积,需确保顶点按顺/逆时针有序、不重复,使用double或long long避免溢出和精度错误;自交多边形需先分解为简单多边形再分别计算。

用 std::vector 存多边形顶点时,怎么算面积?
直接用「鞋带公式」(Shoelace formula),它不依赖凸凹性,只要顶点按顺时针或逆时针顺序排列就行。关键不是写多复杂,而是顺序不能错、坐标类型别溢出。
实操建议:
- 顶点存成
std::vector<:pair double>></:pair>或自定义Point结构,避免用float算面积——小数精度不够容易符号翻转 - 确保首尾不重复:输入是
[(0,0), (2,0), (2,2), (0,2)]就够了,别加个重复的(0,0)进去,否则公式里会多算一轮 - 公式本质是求和
sum += x[i] * y[i+1] - x[i+1] * y[i],最后取绝对值除以 2;下标i+1要模n,C++ 里用(i + 1) % n
double polygonArea(const std::vector<std::pair<double, double>>& pts) {
int n = pts.size();
if (n < 3) return 0.0;
double area = 0.0;
for (int i = 0; i < n; ++i) {
int j = (i + 1) % n;
area += pts[i].first * pts[j].second;
area -= pts[j].first * pts[i].second;
}
return std::abs(area) / 2.0;
}遇到自相交多边形,polygonArea 还准吗?
不准。鞋带公式算的是「有向面积」代数和,自交会导致部分区域正负抵消。比如一个八字形,结果可能接近 0,而不是两个环的面积之和。
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 明明画出来是个大矩形加个小三角,面积却比矩形还小
- 同一组点,只是输入顺序调换(比如把中间某个点提前),结果差几倍
这时候不能硬套公式。得先做「多边形分解」:用算法(如单调链剖分或 ear clipping)拆成若干简单多边形,再逐个调用上面的函数。OpenCV 的 cv::contourArea 默认也假设输入是简单多边形;若传入自交轮廓,文档明确说结果未定义。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
用 int 坐标时,为什么面积算出来是 0?
因为整数乘法中间结果溢出,或者除以 2 时截断。比如顶点都是 int,但 x[i] * y[i+1] 可能远超 INT_MAX,一溢出整个和就崩了。
解决办法很实在:
- 强制转
long long再算:写成(long long)pts[i].x * pts[j].y - 面积结果用
double或long long接,别用int - 如果确定所有坐标 ≤ 1e4,且顶点数 ≤ 1e3,那
long long足够;否则老实用double,它有 52 位有效位,比int安全得多
OpenCV 的 cv::contourArea 和手写函数结果不一样
大概率是坐标顺序或数据类型问题。OpenCV 默认把输入 contour 当作逆时针为正方向,但它的实现底层也是鞋带公式——只是做了符号归一化:返回值恒为正,且内部用了 double 精度累积。
对比时要注意:
- OpenCV 输入是
std::vector<:point></:point>,其中cv::Point是int类型,但函数内部会转double计算 - 你的手写函数如果用
int累加,没转long long,哪怕只差一个点,中间溢出就会导致最终差几百甚至符号相反 - OpenCV 对空 contour 或少于 3 点返回 0;你自己的函数也要加同样校验,别让
n=2时还硬算
真要对齐结果,最稳的方式是:统一用 std::vector<:point2d></:point2d>(即 double 坐标)喂给 OpenCV,再拿它的输出和你手写的 double 版本比。

















