#include
#include
#include
#include
using namespace std;
vector> findNodes(vector>& arr);
bool sortByAngle(vector& a, vector& b);
bool isOrigin(vector& a, vector& b);
bool isOnLeft(vector curNode, vector topMinuOne, vector top);
double distance(vector &a, vector &b);
void test1();
void test2();
vector originPoint;
double originX;
double originY;
int main() {
test1(); //当坐标数组为空时候,测试1
test2(); //当扫描时候有多个坐标在一条直线上时,测试2
}
void test1() {
cout << "test1()输入为空数组:" << endl;
vector> temp;
if (findNodes(temp).size() == 0) {
cout << "test1()输出为空数组,正确" <> temp = { { 1,1 },{ 2,2 },{ 2,0 },{ 2,4 },{ 3,3 },{ 4,2 } };
//vector> temp = { {1,1},{2,1},{3,1},{2,2},{3,3},{2,3},{1,3} };
//vector> temp = { {1,1},{1,1},{1,1},{1,1},{1,1},{1,1} };
cout << "test2()输入是: " << "{
{1,1},{2,2},{2,0},{2,4},{3,3},{4,2}}" << endl;
vector> ans = findNodes(temp);
cout << "test2()输出结果是:{";
for (int i = 0; i < ans.size(); i++) {
cout << '{' << ans[i][0] << "," << ans[i][1] << "},";
}
cout << '}' << endl;
cout << "test2()正确结果是:" << "{
{2,0},{4,2},{2,4},{1,1}}";
}
//Description: 找出凸包上的坐标点,会先找到一个极点然后进行逆时针扫描
vector> findNodes(vector>& arr) {
sort(arr.begin(), arr.end(), isOrigin); //排序目的有两个,一是用于查找第一个节点(左下角)
int nodeNum = arr.size(); //二是为了给坐标点去重
for (int i = 0; i < nodeNum - 1; i++) {
if ((arr[i][0] == arr[i + 1][0]) && (arr[i][1] == arr[i + 1][1])) {
arr.erase(arr.begin() + i);
nodeNum = arr.size();
i--;
}
}
nodeNum = arr.size(); //计算去重后剩下的坐标点的个数
if (nodeNum <= 2) { //数组为空或者坐标点为1,2这些简单情况就直接返回
return arr;
}
originPoint = arr[0];
originX = originPoint[0];
originY = originPoint[1];
sort(arr.begin() + 1, arr.end(), sortByAngle); //根据角度大小进行排序,角度一样大的按照距离小的在前
vector> ans;
ans.push_back(originPoint); //把极点先存入
int i = 1;
ans.push_back(arr[i++]);
int top = 1;
while (i < nodeNum) { //检查每一个节点是否属于凸包
if (isOnLeft(arr[i], ans[top - 1], ans[top])) {
ans.push_back(arr[i++]);
top++;
}
else {
if (ans.size() == 2) { //如果刚开始的几个点都在一条直线上,那么ans里面第二个点会被剔除,导致数组越界
ans.pop_back();
ans.push_back(arr[i++]);
} else {
ans.pop_back();
top--;
}
}
}
return ans;
}
//Description: 判断三点构成的连线的相对位置
bool isOnLeft(vector cur, vector topMinuOne, vector top) {
int cross = (cur[0] - topMinuOne[0])*(top[1] - topMinuOne[1]) - (top[0] - topMinuOne[0])*(cur[1] - topMinuOne[1]); //x1y2-x2y1 计算叉积
if (cross > 0) {
return false;
}
else if (cross < 0) {
return true;
}
else { //叉积等于0的时候,说明点共线,要进行判断一下
if (distance(cur, topMinuOne) > distance(top, topMinuOne)) {
return false;
}
return true;
}
}
bool isOrigin(vector& a, vector& b) {
if (a[1] == b[1]) { //纵坐标相等的时候,横坐标小的在前
return a[0] < b[0];
}
return a[1] < b[1];
}
double distance(vector &a, vector &b) {
return (pow((a[0] - b[0]), 2) + pow((a[1] - b[1]), 2));
}
bool sortByAngle(vector& a, vector& b) {
if (abs(atan2(a[1] - originY, a[0] - originX) - atan2(b[1] - originY, b[0] - originX)) < 1e-8) { //浮点数比较是否相等,只能取一个范围
return distance(a, originPoint) < distance(b, originPoint);
}
return atan2(a[1] - originY, a[0] - originX) < atan2(b[1] - originY, b[0] - originX);
}