凸包(Convex Hull)问题的Gift-Wrapping算法


前言

在软件构造lab1中,要求用Java语言编写代码,完成凸包(Convex Hull)问题的解决,算法有很多,本文仅介绍实验指导书建议采用的Gift-Wrapping算法。


一、凸包问题是什么?

凸包(Convex Hull)是一个计算几何(图形学)中的概念。在一个实数向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包。X的凸包可以用X内所有点(X1,…Xn)的凸组合来构造.
在二维欧几里得空间中,凸包可想象为一条刚好包著所有点的橡皮圈。
用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它是能包含点集中所有的点的最小的凸多边形。

二、Gift-Wrapping算法

1.简述思路

顾名思义,所有的点就是“礼物”,找凸包的过程就是把他们包装起来的过程,因此本算法从一个起始点开始,沿某一初始方向,将所有点均包裹起来,得到的路径经过的点即所求结果。

2.具体实现

难点在于如何从一个点,前进到下一个点,实现逐步的包装操作。
由于该问题出现在实验的一步中,而实验的前一步刚刚完成了一个方法,实现了计算已知起点与起始方向,计算转向终点的方向转动的角度大小,该方法实现代码如下:

public static double expandedCalculateBearingToPoint(double currentBearing, double currentX, double currentY, double targetX, double targetY) {
	double x = targetX - currentX;
	double y = targetY - currentY;
	double angle = Math.toDegrees(Math.atan2(y, x));
	angle = 90 - angle - currentBearing;
	angle = angle >= 0 ? angle : (angle + 360);
	return angle;
}

函数名中的expended是因为原方法的两点横纵坐标是int,本方法拓展到double类型。

然后调用该方法完成凸包问题的求解,该方法实现代码如下:

public static Set<Point> convexHull(Set<Point> points) {
	if (points.size() <= 3)
		return points;

	HashSet<Point> result = new HashSet<Point>();
	Point start = points.iterator().next();
	for (Point p : points) {
		if (p.x() < start.x() || (p.x() == start.x() && p.y() < start.y()))
			start = p;
	}
	result.add(start);

	double currentBearing = 0; // 初始化方向为向上
	double angle, min;
	Point current = start;
	Point target = points.iterator().next();
	if (target == start)
		target = points.iterator().next();

	while (target != start) {
		min = 360;
		for (Point p : points) {
			if (p == current)
				continue;
			angle = expandedCalculateBearingToPoint(currentBearing, current.x(), current.y(), p.x(), p.y());	
			if ((angle < min) || ((angle == min) && (calculateDistance(current.x(), current.y(), p.x(), p.y()) > calculateDistance(current.x(), current.y(), target.x(), target.y())))) {
				target = p;
				min = angle;
			}
		}
		result.add(target);
		current = target;
		currentBearing = min;
	}
	return result;
}

总结

先确定最左上角的点(也可以是其他的某个一定在凸包边界上的点)为初始点,确定y轴正方向(也可以是其他方向,保证该方向所在直线将图分成的两侧,一侧不含点)为初始朝向;选取下一个点的标准:利用Problem6中设计的函数的拓展版(点的坐标拓展到double)计算从上一个点到下一个点的角度最小,多者最小选距离(自己构造了一个函数用于求两点间距离)最大者为下一个点,直到找了一圈后回到初始点。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值