课程:计算几何
书籍:计算几何:算法与应用
极点:构成凸包的顶点,它具有这样的性质:经过该点,总能找到一条直线,使得其他所有点都在该直线的同一侧。
根据该思路,极点不会处于其他顶点所构成的三角形内部。因此我们只需要所有点进行它是否在其他顶点所组成的三角形内部做判断,即可得出所有的极点。
如何判断一个点是否在三角形内:按逆时针方向去看三角形的边,如果一个点在三角形内部,则该点总在三角形所有边的左侧。因此我们只需要做三此点是否在边的左侧的判断即可。
如何判断一个点是否在一条向量的左侧:根据两个向量叉乘的符号去判断。S为判断点,AB为向量,如果AB × AS > 0 则 点S在向量AB的左侧;如果AB × AS = 0 点S在直线AB上;如果AB × AS < 0 则 点S在向量AB的右侧。
代码:
Point.h
#pragma once
#ifndef POINT_H
#define POINT_H
#include<iostream>
using namespace std;
class Point {
public:
int index;
float x, y;
bool isExtremePoint;
public:
Point() { index = 0; x = y = 0.0f; isExtremePoint = false; }
~Point() {}
Point(int index, float xx, float yy) {
this->index = index;
x = xx; y = yy;
}
Point(Point &temp) :index(temp.index), x(temp.x), y(temp.y), isExtremePoint(temp.isExtremePoint){}
friend ostream& operator<<(ostream& os, Point& temp) {
os << "Point index: " << temp.index << " (x,y): " << temp.x << "," << temp.y << endl;
return os;
}
};
#endif // !POINT_H
Main.cpp
/* indere 2018/6/22
* O(n^4)构造凸包算法思路为:如果一个点不在其他点所组成的三角形内部,则该点是极点
* 输入:顶点数以及顶点坐标
* 输出:极点编号(看情况是否按Counter-Clockwise输出)
/
/* 输入:
10
7 9
-8 -1
-3 -1
1 4
-3 9
6 -4
7 5
6 6
-6 10
0 8
*/
#include "Point.h"
Point *points;
int pointsize;
void Initialize(); //初始化points数组
void ConstructConvexHull(Point* points); //根据Point数组信息 构造凸包
bool InTriangle(int p1, int p2, int p3, int s); //判断点s是否在p1,p2,p3做组成的三角形内
int ToLeft(int v1, int v2, int s); //ToLeft Test
int main() {
Initialize();
ConstructConvexHull(points);
for (int i = 0; i < pointsize; i++) {
if (points[i].isExtremePoint)
cout << points[i];
}
return 0;
}
void Initialize() {
cin >> pointsize;
points = new Point[pointsize];
for (int i = 0; i < pointsize; i++) {
float x, y;
cin >> x >> y;
points[i] = Point(i + 1, x, y);
}
}
void ConstructConvexHull(Point* points) {
for (int i = 0; i < pointsize; i++)
points[i].isExtremePoint = true;
for (int i = 0; i < pointsize; i++) {
for (int j = i + 1; j < pointsize; j++) {
for (int k = j + 1; k < pointsize; k++) {
for (int s = 0; s < pointsize; s++) {
if (s != i && s != j && s != k && InTriangle(i, j, k, s)) { //如果s点在i,j,k所组成的三角形中,则s为非极点
points[s].isExtremePoint = false;
}
}
}
}
}
}
bool InTriangle(int p1, int p2, int p3, int s) {
bool result = false;
int t1 = ToLeft(p1, p2, s);
int t2 = ToLeft(p2, p3, s);
int t3 = ToLeft(p3, p1, s);
if (t1 == t2 && t2 == t3 && t3 == t1 && t1 != 2) //最后一个判断是为了判断 这几个点不共线
result = true;
return result;
}
int ToLeft(int v1, int v2, int s) {
float result = (points[v2].x * points[s].y + points[v1].x * points[v2].y + points[v1].y * points[s].x)
- (points[v1].y * points[v2].x + points[v1].x * points[s].y + points[v2].y * points[s].x);
if (result > 0.0f) //左侧
return 1;
if (result == 0.0f) //共线
return 2;
if (result < 0.0f) //右侧
return -1;
}