最近有需求要判断多边形是否为矩形,网上查了资料,有介绍说计算所有点间的距离,用sort进行排序,unique去重后如果只留下3组数据,并且符合勾股定理,则为矩形。代码实现如下:
bool IsRectangle(const std::vector<Eigen::Vector2d>& corners) {
if (corners.size() != 4) return false;
auto GetLengthPow = [](Eigen::Vector2d p1,
Eigen::Vector2d p2) {
return pow(p1(0) - p2(0), 2) + pow(p1(1) - p2(1), 2);
};
double length[6] = {GetLengthPow(corners.at(0), corners.at(1)),
GetLengthPow(corners.at(0), corners.at(2)),
GetLengthPow(corners.at(0), corners.at(3)),
GetLengthPow(corners.at(1), corners.at(2)),
GetLengthPow(corners.at(1), corners.at(3)),
GetLengthPow(corners.at(2), corners.at(3))};
std::sort(length, length + 6);
int size = std::unique(length, length + 6) - length;
if (size == 2) {
return true;
}
if (size == 3) {
// 勾股定理
if (length[0] + length[1] - length[2] < 1e-6) {
return true;
}
return false;
} else {
return false;
}
}
但是问题在double类型的计算会有精度损失,用以下代码做了验证
#include <iostream>
#include <math.h>
#include <algorithm>
int main(){
double a = 1.0 + 20.2 +30.03;
double b = 51.23;
std::cout << "a == b : " << (a == b) << std::endl;
double len[2] = {a, b};
auto size = std::unique(len, len + 2) - len;
std::cout << "size = " << size << std::endl;
}
发现unique去重会受到double精度的影响,a和b理论上是一致的结果的size应为1,但由于double类型,a和b并不相等,查阅unique的源码,其中的判断就是直接 == 来判断相同并去重。因此unique用来去重double并不合适。
所以实现方法暂时修改为:判断对边相等,且有相邻两条边垂直。
如果多边形的轮廓没有顺序,可以通过找到max_y 以此点为起点,计算其与其他所有轮廓顶点的余弦值,从小到大排序则为逆时针顶点排序。