一个计算凸包的算法

凸包是一个计算几何(图形学)中的概念。

在一个实数向量空间V中,对于给定的集合X,所有包含X的凸集的交集S被称为X的凸包。

X的凸包可以用X内所有点(X1,...Xn)的线性组合来构造.

在二维欧几里得空间中,凸包可想象为一条刚好包著所有点的橡皮圈。

用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能包含点集中所有的点。如下图所示:

一个比较简单的实现方法如下:

首先将所有点放在平面直角坐标系中,然后找到最左(横坐标相等则取纵坐标更小的)的点,这个点加入凸包集合。然后寻找与该点相对角度最小的点并加入。(起始角度为零且所有角度都是相对y轴正方向,顺时针旋转)。实现代码如下:

public static Set<P2.turtle.Point> convexHull(Set<P2.turtle.Point> points) {
    //throw new RuntimeException("implement me!");
    //首先处理点的坐标
    //点的个数小于等于3时,所有点都在凸包内
    if (points.size() <= 3)
        return points;
    Set<Point> convexHullPoints = new HashSet<Point>();
    Point a = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE);
    //先找出在平面上最左下角的点
    for(Point i : points){
        if(i.x() < a.x() || (i.x() == a.x() && i.y() < a.y()))
            a = i;
    }
    convexHullPoints.add(a);
    Point curpoint = a, nextpoint = null;
    double angle = 0, mintheta = 360, theta = 0, distance = 0;
    while(nextpoint != a) {
        for(Point i : points) {//类似calculateBearingToPoint的方法,找出使得旋转角度最小的点
            //运用反三角函数计算目标点与当前点所成斜线与x轴正向的夹角
            double angle1 = Math.atan2(i.y() - curpoint.y(), i.x() - curpoint.x()) * 180.0 / Math.PI;
            //角度为负的,调整为正值
            if(angle1 < 0)
                angle1 += 360.0;
            //计算斜线与y轴正向之间的夹角(y轴为始边,顺时针方向为正向),再减去当前偏移角度
            double bearing = (360 - angle1 + 90 >= 360 ? 90 - angle1 : 360 - angle1 + 90) - angle;
            //最后调整为0-360°之间
            if(bearing < 0)
                theta = 360.0 + bearing;
            else
                theta = bearing;
            //查找使得旋转角度最小的角
            if((!convexHullPoints.contains(i) || (i == a && curpoint != a)) && theta < mintheta) {
                mintheta = theta;
                nextpoint = i;
                distance = Math.sqrt((i.y() - curpoint.y())*(i.y() - curpoint.y())+(i.x() - curpoint.x())*(i.x() - curpoint.x()));
            }
            //当旋转角度相同时,选择距离当前点更远的点
            if((!convexHullPoints.contains(i) || (i == a && curpoint != a)) && theta == mintheta) {
                if(Math.sqrt((i.y() - curpoint.y())*(i.y() - curpoint.y())+(i.x() - curpoint.x())*(i.x() - curpoint.x())) > distance) {
                    nextpoint = i;
                    distance = Math.sqrt((i.y() - curpoint.y())*(i.y() - curpoint.y())+(i.x() - curpoint.x())*(i.x() - curpoint.x()));
                }
            }
        }
        convexHullPoints.add(nextpoint);
        curpoint = nextpoint;
        angle += mintheta;
        if(angle > 360)
            angle -= 360;
        mintheta = 360;
    }
    return convexHullPoints;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值