Gift Wrapping求凸包算法需要注意的三个问题(Java实现)

简介:Gift Wrapping算法顾名思义,是将点集看作礼物,像用礼物带对礼物进行包装一样,一点点缠好就求得了这个点集的一个凸包。更形象的比喻是,将点集中的点比作一根根钉在木板上的钉子,再用一根绳子从外围将这些钉子包围起来。

Gift Wrapping的具体实现步骤是这样的:

  1. 在点集中随意选择一个必然在凸包上的点,可以根据该点的横纵坐标选出一个横坐标最小(大),纵坐标最小(大)的点,共四种组合;

  2. 以该点为出发点进行凸包的构建,一点点扯长我们手里这根“绳子”,扯长这根绳子的办法就是计算夹角(当然也可以计算叉乘),用Java中带有的Math.atan方法计算这根绳子需要转过的最小角度就可以了,那个构成最小角度的点即为可以加入凸包的点;

  3. 对上一步进行循环直到加入的点为最初加入的点就可以了。

步骤很清晰,但是实现过程中有三点需要注意:

  • 对于个数小于3的顶点集需要分类:
		int num = points.size();
		if (num <= 2) {
			convexHullPoints = points;// 0、1、2个点时,凸包即为其本身
		}
  • 计算角度时要注意分类:arctan计算的角度大小范围为(- π 2 \frac{\pi}{2} , π 2 \frac{\pi}{2} ),因此以源点src为直角坐标系坐标原点,目标点end在一、三象限时大小为正数( α \alpha γ γ ),在二、四象限时为负数( β β δ δ );
    在这里插入图片描述
    进行分类,在一、四象限为一类,二、三象限为另一类,这当中的sumAngle为之前所有加点入凸包转过的角度minAngle之和。

    double tmpAngle = 90 - sumAngle - Math
    							.toDegrees(Math.atan((array[i].y() - array[end].y()) / (array[i].x() - array[end].x())));
    					if (array[i].x() < array[end].x())
    						tmpAngle += 180;
    					if (tmpAngle < 0)
    						tmpAngle += 360;//算当前点与end点的角度大小 
    

    若sumAngle为0,即图中y轴,根据这种方法对上图进行测试:

    • 一象限的点:转动 ( 90 0 α ) ° (90 - 0 - α)\degree
    • 二象限的点:转动 ( 90 0 β ) ° (90 - 0 - β)\degree
    • 三象限的点:转动 ( 90 0 γ + 180 ) ° (90 - 0 - γ + 180)\degree
    • 四象限的点:转动 ( 90 0 δ + 180 ) ° (90 - 0 - δ + 180)\degree
  • 最后一点要注意所求的凸包是最大还是最小,注意在凸包集形成的凸多边形边上的点,如果所求为最小凸包,需要避免加入这些点,反之则必须要加入这些点。在这里引入变量distance,在角度相同的情况下,根据要求选择合适的点加入凸包。

    if (tmpAngle < minAngle) {
    	minAngle = tmpAngle;
    	current = i;
    } else if (tmpAngle == minAngle) {//求最小凸包,凸包边上的点不要包括
    	if (Math.pow(array[i].x() - array[end].x(), 2) + Math.pow(array[i].y() - array[end].y(),
    			2) > Math.pow(array[current].x() - array[end].x(), 2)
    					+ Math.pow(array[current].y() - array[end].y(), 2))
    		current = i;
    }
    

以上就是我在Gift Wrapping求凸包算法中发现需要注意的三个问题。

发布了8 篇原创文章 · 获赞 3 · 访问量 301

猜你喜欢

转载自blog.csdn.net/weixin_43872188/article/details/104602057