Computer Geometric - convex hull

Convex hull: In a real vector space V, for a given set of X, X convex set containing all the intersection is referred to as X convex hull.
What do you mean, I did not understand. After browsing through the many blog articles, my understanding of the convex hull is as follows:
given a set of discrete points, obtained by surrounding the entire set of edges of discrete points.
For example, in a set of N random wall nails, and with a sufficiently large rubber band surrounds the nails, then after releasing the rubber band, rubber band range is the convex hull.
Here Insert Picture Description
Then the convex hull algorithm, the input is a set of discrete points, can be composed of the return point of the convex hull of the points are connected together is the convex hull.
Convex hull algorithm is used Graham scan method, and Jarvis stepping approach
here we introduce the Graham scan method:
Step:

  1. Obtaining a minimum y-axis, x-axis from the minimum point P0 discrete points set S. (If the minimum y-axis with a plurality of points on the x axis taking the minimum point)

  2. S calculated in the other points to point P0 polar angle, and according to the ascending order of the sort set S1 (the same polar angle, taken from the top most stage), may be determined by the ordering and sorting point PO after a first set point S1, the point P1 is a point of the convex hull, the convex hull join list.

  3. S1 acquired from a lower point (P2), calculating the point P2 located in the line segment (P0,01) left or right.

  4. If left, the point P2 is added to the queue convex-hull point, if the right side, the point (P1) is removed once the addition of the recalculated positional relationship between the point P1 and the line set (here P1 is removed, there is only one list, it is added directly)

  5. Repeat steps 3-4, until there is no known point S1.
    Read also in trouble? That move directly to see Zhang map:

Here Insert Picture Description
Figure should be very intuitive, here we come to realize the following, Untiy platform, language is C #:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class GrahamScan : MonoBehaviour {
    //离散的点
    public Transform[] Points;
    //组成边的顶点集合
    public List<Transform> ePoint = new List<Transform>();

    private bool IsFinsh = false;
    void Start()
    {
        Aritmetic();
    }

    //算法
    void Aritmetic()
    {
        Transform bp = BasePoint();
        bp.name = "P0";
        ePoint.Add(bp);
        Transform[] polarSort = PolarSort(bp);
        for (int i = 0; i < polarSort.Length; i++)
        {
            if (polarSort[i] == bp) continue;
            polarSort[i].name = "P" + (i + 1);
        }
        //通过排序,而可以得知 第一个点肯定在凸边上
        ePoint.Add(polarSort[0]);
        StartCoroutine(Ia(polarSort));
    }

    IEnumerator Ia(Transform[] polarSort)
    {
        for (int i = 1; i < polarSort.Length; i++)
        {
            yield return new WaitForSeconds(1);
            ePoint.Add(polarSort[i]);
            float d = PointDir(ePoint[ePoint.Count-1].position, ePoint[ePoint.Count - 2].position, ePoint[ePoint.Count - 3].position);
            if (d <= 0)
                continue;
            while (true)
            {
                yield return new WaitForSeconds(1);
                ePoint.RemoveAt(ePoint.Count-2);
                d = PointDir(ePoint[ePoint.Count - 1].position, ePoint[ePoint.Count - 2].position, ePoint[ePoint.Count - 3].position);
                if (d < 0)
                    break;
            }
        }
        IsFinsh = true;
    }

    void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        if (!IsFinsh)
        {
            for (int i = 0; i < ePoint.Count - 1; i++)
                Gizmos.DrawLine(ePoint[i].position, ePoint[i + 1].position);
            return;
        }

        for (int i = 0; i < ePoint.Count; i++)
        {
            if (i == ePoint.Count - 1)
            {
                Gizmos.DrawLine(ePoint[i].position,ePoint[0].position);
                continue;
            }
            Gizmos.DrawLine(ePoint[i].position,ePoint[i+1].position);
        }

    }

    /// <summary>
    /// 获取基点P0
    /// </summary>
    /// <returns></returns>
    Transform BasePoint()
    {
        //取y值最小 如果多个y值相等,去x最小(这里y 我们取z)
        Transform minPoint = Points[0];
        for (int i = 1; i < Points.Length; i++)
        {
            if (Points[i].position.z < minPoint.position.z)
                minPoint = Points[i];
            else if (Points[i].position.z < minPoint.position.z)
                minPoint = Points[i].position.x < minPoint.position.x ? Points[i] : minPoint;
        }
        return minPoint;
    }
    /// <summary>
    /// 获取点的方向 =0 在线上 <0在左侧 >0在右侧
    /// </summary>
    /// <param name="p"></param>
    /// <param name="p1"></param>
    /// <param name="p2"></param>
    /// <returns></returns>
    float PointDir(Vector3 p, Vector3 p1, Vector3 p2)
    {
        Vector3 v1 = p1 - p;
        Vector3 v2 = p2 - p1;
        float f = v1.x * v2.z - v2.x * v1.z;
        return f;
    }

    /// <summary>
    /// 极角排序
    /// </summary>
    /// <param name="bp"></param>
    /// <returns></returns>
    Transform[] PolarSort(Transform bp)
    {
        List<Transform> p = new List<Transform>();
        for (int i = 0; i < Points.Length; i++)
        {
            //如果是自己,则跳过
            if (Points[i] == bp) continue;
            Vector3 v = Vector3.zero;
            float e = GetProlar(Points[i], bp,out v);
            int index = -1;
            for (int j = 0; j < p.Count; j++)
            {
                Vector3 v1 = Vector3.zero;
                float e1 = GetProlar(p[j],bp,out v1);
                if (e1 > e)
                {
                    index = j;
                    break;
                }
                if (e1 == e && v.magnitude < v1.magnitude)
                {
                    index = j;
                    break;
                }
            }
            if (index == -1)
            {
                p.Add(Points[i]);
                continue;
            }
            p.Insert(index,Points[i]);
        }
        return p.ToArray();
    }
    /// <summary>
    /// 获取极角
    /// </summary>
    /// <param name="pos1"></param>
    /// <param name="pos2"></param>
    /// <returns></returns>
    float GetProlar(Transform pos1, Transform pos2,out Vector3 v)
    {
        v = pos1.position - pos2.position;
        return Mathf.Atan2(v.z,v.x);
    }

}

According to the above steps to achieve here is a moment, sorting using insertion sort, for easy viewing using coroutine exhibited animation effects.
Because the Y-axis orthogonal views used herein, therefore the above said modification of the Y-axis Z-axis.
When testing, the creation of discrete points (GameObject) drag Points list.

Published 28 original articles · won praise 18 · views 20000 +

Guess you like

Origin blog.csdn.net/qq_18192161/article/details/90024238
Recommended