软件构造:二维凸包问题求解

1.问题概述:

给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点。

如下图所示,给定点的集合<0,1,2,3,4,5,6,7,8,9,10>,将最外层的点<0,1,3,6,7,10,9>连接起来,形成了一个凸多边形,这个多边形就是该点集合的凸包,所有的点都在凸包里面。

在Lab1中,关于凸包有如下细节:

1) 当凸包中的点少于3个的时候,所有的点都在凸包中;

2)当多个点在凸包顶点的连线的时候,选择距离最远的两个点。如上图中红色的点和9、10号点,这个时候,凸包集合中包含红的的0号点和10号点,但是9号点不在凸包集合中

所以凸包问题就是求解凸包顶点集合的问题。

2.Gift-Wrapping算法求解凸包问题

Gift-Wrapping算法又叫Jarvis步进法,采用一种“打包”的方法来计算点集合的凸包。算法的时间复杂度为O(hn),其中n是所有点的数量,h是凸包顶点的数量。

首先寻找一个点作为极点P0,要求这个点的x坐标最小,如果有多个这样的点,选择y坐标最小的点。这个点一定在凸包上。

接下来以P0作为极点,y轴作为极轴,寻找相对与P0的相对极角最小的一个点,如果有多个这样的点,选择距离P0最远的点加入到凸包集合。

假设选择了P1,加入了凸包集合,接下来选择P1作为新的极点,P0P1连线的方向作为新的极轴,继续寻找下一个点加入凸包集合。

以此类推,直到遇到P0后,说明形成和封闭图形,寻找凸包完毕。

 

实现的算法如下:

  public static Set<Point> convexHull(Set<Point> points) {
    	Set<Point> convexHulls = new  HashSet<Point>();//存放凸包顶点的集合
    	Set<Point>copyofpoints = new  HashSet<Point>();//复制点的集合
    	/** 复制点到copyofpoints集合*/
    	for(Point temp:points)
		{
    		copyofpoints.add(temp);
		}
    	/**
    	 * 当点的个数低于3个时,点全部在凸包点集合中
    	 */
    	if(copyofpoints.size()<3)
    	{
    		convexHulls=copyofpoints;
    		return convexHulls;
    	}
    	
    	/**寻找第一个极点,位置是左下角*/
    	Point p0 = new Point(Double.MAX_VALUE, Double.MAX_VALUE);
    	for (Point item : copyofpoints) {
            if (item.x() < p0.x() || (item.x() == p0.x() && item.y() < p0.y()))
                p0 = item;
        }
    	Point currentPoint = p0;
    	double currentAngle = 0;
    	convexHulls.add(currentPoint);//add p0
    	copyofpoints.remove(p0);
    	currentPoint = findNextPoint(copyofpoints,currentPoint,currentAngle);
		convexHulls.add(currentPoint);
		copyofpoints.remove(currentPoint);
		copyofpoints.add(p0);
    	do
    	{
    		
    		currentPoint = findNextPoint(copyofpoints,currentPoint,currentAngle);
    		convexHulls.add(currentPoint);
    		copyofpoints.remove(currentPoint);
    		
    	}while(currentPoint!=p0);

    	return convexHulls;
        //throw new RuntimeException("implement me!");
    }
     //寻找极角最小的下一个点
    public static Point findNextPoint(Set<Point> copyofpoints,Point currentPoint,double currentAngle)
    {
    	Point tempPoint = new Point(0,0);
    	double minAngle = 360.0;
    	double tempAngle = 0;
    	double maxDistance=0;
    	for(Point item : copyofpoints)
    	{
			tempAngle=MycalculateBearingToPoint(currentAngle, currentPoint.x(), currentPoint.y(),
                    item.x(), item.y());
			if(tempAngle<minAngle)
			{
				minAngle = tempAngle;
				tempPoint = item;
				maxDistance = Distance(tempPoint,currentPoint);
			}
			if(tempAngle==minAngle&&Distance(item,currentPoint)>maxDistance)
			{
				maxDistance= Distance(item,currentPoint);
				minAngle = tempAngle;
				tempPoint = item;
				
			}
    	}
		currentPoint = tempPoint;
		currentAngle +=minAngle;
		if(currentAngle>=360.0)
		{
			currentAngle-=360.0;
		}
		minAngle = 360.0;
		return currentPoint;
    }
//计算极角
	public static double MycalculateBearingToPoint(double currentBearing, double currentX, double currentY,
		double targetX, double targetY) {
		double angle = 0;
		double ax = targetX - currentX;
		double ay = targetY - currentY;
		double bx = 0;
		double by = 1;
		double cosangle = (ax * bx + ay * by) / (Math.sqrt(Math.pow(ax, 2.0) + Math.pow(ay, 2.0)));

		double Targetangle = Math.toDegrees(Math.acos(cosangle));
		if (ax < 0) {
			Targetangle = 360.0 - Targetangle;
		}
		angle = Targetangle - currentBearing;
		if (angle < 0) {
			angle += 360.0;
		}
		return angle;

}
	//计算两点间的距离
	public static double Distance(Point currentPoint ,Point targetPoint) {
		
		double distance= 0;
		distance = Math.sqrt(Math.pow(currentPoint.x()-targetPoint.x(), 2.0)+Math.pow(currentPoint.y()-targetPoint.y(), 2.0));
		return distance;
	}

更多有关于凸包问题的算法参考凸包问题——概述 - 知乎 (zhihu.com)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值