C++实现凸包Graham_scan算法

 算法原理CSDN或者知乎上都有,不难。

代码主要参考C语言实现凸包Graham_scan算法

但是一只小蒟蒻的代码没有经过测试,细节上有一些小问题。我将代码修改测试后,放下下面,防走失。

将vector结构去除,就可以改为C语言代码。

#include<math.h>
#include<vector>

#define PI 3.1415926

typedef struct Point {
	int x, y;
	double angle;
}Point;

int less(Point a, Point b) {		//定义点a小于点b法则(排序用)
	if (a.angle != b.angle) 
		return a.angle < b.angle;
	else return 
		a.x < b.x;
}

int ifAnticlockwise(Point a, Point b, Point c) {	//是否为逆时针
	int crossProduct = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);	//求向量积
	return crossProduct > 0;	//向量积为正表示逆时针
}

std::vector<Point> Graham_scan(std::vector<Point> point) {

	double sx = HUGE_VAL, sy = HUGE_VAL;
	for (int i = 0; i < point.size(); i++) {		//寻找起始点
		if (point[i].y < sy)
			sx = point[i].x, sy = point[i].y;
		else if (point[i].y == sy && point[i].x < sx)
			sx = point[i].x;
	}
	for (int i = 0; i < point.size(); i++) {		//求夹角
		if (point[i].x == sx && point[i].y == sy)
			point[i].angle = 0;
		else if (point[i].x == sx)
			point[i].angle = PI / 2;
		else {
			point[i].angle = atan((point[i].y - sy) * 1.0 / (point[i].x - sx));
			if (point[i].angle < 0)
				point[i].angle = PI + point[i].angle;
			//转换为与x轴正方向夹角
		}
	}
	for (int i = 0; i < point.size() - 1; i++) {
		for (int j = i + 1; j < point.size(); j++) {	//冒泡排序
			if (less(point[j], point[i])) {
				Point temp = point[i];
				point[i] = point[j];
				point[j] = temp;
			}
		}
	}
	int cnt = 3;	//栈顶指针
	for (int i = 3; i < point.size(); ) {
		if (ifAnticlockwise(point[cnt - 2], point[cnt - 1], point[i]))
			point[cnt++] = point[i++];
		else
			point[--cnt] = point[i];
	}
	std::vector<Point> convex_hull;
	for (int i = cnt - 1; i >= 0; i--) {	//逆序输出
		convex_hull.push_back(point[i]);
	}
	return convex_hull;
}

 测试用main,将点与凸包均绘制在图上,结果正确与否比较直观。

#include<stdio.h>
#include"opencv2/opencv.hpp"

int main() {
	srand((unsigned)time(NULL));
	int n = 19, minx = 1, maxx = 98, miny = 1, maxy = 98;
	
	std::vector<Point> point;
	for (int i = 0; i < n; i++) {	//生成随机坐标
		Point pt;
		pt.x = rand() % (maxx - minx + 1) + minx;
		pt.y = rand() % (maxy - miny + 1) + miny;
		point.push_back(pt);

	}
	//point[0].x = 6; point[0].y = 80;
	//point[1].x = 72; point[1].y = 18;
	//point[2].x = 62; point[2].y = 65;
	//point[3].x = 62; point[3].y = 12;
	//point[4].x = 6; point[4].y = 71;
	//point[5].x = 79; point[5].y = 48;
	//point[6].x = 91; point[6].y = 44;
	//point[7].x = 4; point[7].y = 65;
	//point[8].x = 87; point[8].y = 2;
	//point[9].x = 31; point[9].y = 56;
	//point[10].x = 79; point[10].y = 48;
	//point[11].x = 67; point[11].y = 78;
	//point[12].x = 19; point[12].y = 49;
	//point[13].x = 48; point[13].y = 38;
	//point[14].x = 25; point[14].y = 26;
	//point[15].x = 39; point[15].y = 50;
	//point[16].x = 65; point[16].y = 98;
	//point[17].x = 24; point[17].y = 94;
	//point[18].x = 78; point[18].y = 62;

	for (int i = 0; i <n; i++) {
		printf("point[%d].x = %d;point[%d].y = %d;\n", i,point[i].x, i, point[i].y);
	}

	cv::Mat showMat(100, 100, CV_8UC1, cv::Scalar(0));
	for (int i = 0; i < n; i++) {
		cv::circle(showMat, cv::Point(point[i].x, point[i].y), 2, cv::Scalar(255));
	}

	std::vector<Point> convex_hull = Graham_scan(point);

	for (int i = 1; i < convex_hull.size(); i++) {	//逆序输出
		cv::line(showMat, cv::Point(convex_hull[i].x, convex_hull[i].y), cv::Point(convex_hull[i - 1].x, convex_hull[i - 1].y), cv::Scalar(125), 1, cv::LINE_4);
	}
	cv::line(showMat, cv::Point(convex_hull[0].x, convex_hull[0].y), cv::Point(convex_hull.back().x, convex_hull.back().y), cv::Scalar(200), 1, cv::LINE_4);

	return 0;
}
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值