求凸包点和面积及周长

/**
Author: LinZhiQ
Date: 2018-10-01 17:28
Graham扫描法  求凸包
*/
#include
using namespace std;
const double eps = 1e-8;
const double PI = acos(-1.0);

struct Point {
	double x,y;

	Point() {}

	Point(double _x, double _y) {
		x = _x;
		y = _y;
	}

	Point operator -(const Point &b)const {
		return Point(x - b.x, y - b.y);
	}// (点 a - 点 b) 表示以 b 为坐标轴原点重新定义 a 的坐标

	double operator ^(const Point &b)const {
		return x * b.y - y * b.x;
	}//Cross 比较 点 a 与 点 b 到原点 连线的斜率 ,a的斜率小则返回值 大于零,等于零表示在同一直线
	double operator *(const Point &b)const {
		return x * b.x + y * b.y;
	}//Dot	点自己 乘 自己 表示 点到原点距离的平方 也就是点乘

	void transXY(double B) {
		double tx = x,ty = y;
		x = tx * cos(B) - ty * sin(B);
		y = tx * sin(B) + ty * cos(B);
	}
} p[105], lis[105];

bool CheckCross(Point a, Point b, Point c){   // 判断点 c 是否在 直线 ab 左侧 
	if((c ^ a) >= 0 && (b ^ c) >= 0 && ((a - b) ^ (c - b)) >= 0){
		return true; 
	}
	return false;
// 求交叉积(ab,ac)
//	return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); 
// 返回值小于0表示c在ab右侧,大于0则在左侧
} 

bool cmp1(const Point &a, const Point &b) {
	return (a.x != b.x ? a.x < b.x : a.y < b.y);
}	// 按照点的 y 坐标从小到大,x 坐标从小到大 (逆时针)

bool cmp2(const Point &a, const Point &b) {
	return ((a ^ b) == 0 ? (a * a) < (b * b) : (a ^ b) > 0);
}	// 极角排序,如果 a与b 在同一直线,那就与原点距离近的优先,否则极角小的优先

int T, n, m;

void PolarAngleSort(){	// 极角排序  
	sort(p + 1, p + 1 + n, cmp1);
	for(int i = 2;i <= n;i++){
		p[i] = p[i] - p[1];
	}
	p[1].x = p[1].y = 0;
	sort(p + 1, p + 1 + n, cmp2);
}

void ConvexHull() {
	PolarAngleSort();
	lis[1] = p[1];	// 起点 
	lis[2] = p[2];	// 前两个点与起点三点可构成面 
	lis[3] = p[3];
	m = 3;
	for(int i = 4;i <= n;i++){
		while(CheckCross(p[i],lis[m - 1],lis[m]) && m > 2){ // 把被新点包围的点全部删去 
			m--;
		}
		lis[++m] = p[i];
	}
}

double getArea() { // 求面积 
	double area = 0;
	for(int i = 2; i <= m - 1; i++) {
		area += ((lis[i] - lis[1]) ^ (lis[i + 1] - lis[1]));
	}
	return fabs(area) / 2.0;
}

double dis(const Point &a, const Point &b){
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

double getPerimeter(){ //求周长 
	double sum = 0;
    for(int i = 2; i <= m; i++){
        sum += dis(lis[i - 1],lis[i]);
    }
    sum += dis(lis[m], lis[1]);
    return sum;
} 

int main() {
	scanf("%d",&T);
	while(T--) {
		scanf("%d",&n);
		for(int i = 1; i <= n; i++) {
			scanf("%lf %lf",&p[i].x,&p[i].y);
		}
		ConvexHull();
		for(int i = 1; i <= m; i++) {
			printf("(%lf,%lf)\n",lis[i].x,lis[i].y);
		}
		printf("%lf %lf\n",getArea(),getPerimeter());
	}
	return 0;
}

 

你可能感兴趣的:(凸包)