项目需求:在UI上任意点击几个点,点击完成后,找到最外围的点。
20240521_143301
代码示例:将点传入方法中即可
// 计算凸包的Graham扫描算法
public static List<Vector2> CalculateConvexHull(List<Vector2> points)
{
if (points.Count < 3)
{
Debug.LogError("点的数量少于3个,无法计算凸包");
return new List<Vector2>();
}
// 复制点列表
List<Vector2> sortedPoints = new List<Vector2>(points);
// 按y坐标排序,如果y坐标相等按x坐标排序
sortedPoints.Sort((a, b) =>
{
if (a.y != b.y)
return a.y.CompareTo(b.y);
return a.x.CompareTo(b.x);
});
// 起点为排序后第一个点
Vector2 startPoint = sortedPoints[0];
sortedPoints.RemoveAt(0);
// 按极角排序
sortedPoints.Sort((a, b) =>
{
float angleA = Mathf.Atan2(a.y - startPoint.y, a.x - startPoint.x);
float angleB = Mathf.Atan2(b.y - startPoint.y, b.x - startPoint.x);
return angleA.CompareTo(angleB);
});
// 创建栈用于存储凸包点
Stack<Vector2> hull = new Stack<Vector2>();
hull.Push(startPoint);
hull.Push(sortedPoints[0]);
for (int i = 1; i < sortedPoints.Count; i++)
{
Vector2 top = hull.Pop();
// 检查方向(逆时针)
while (hull.Count >= 1 && CrossProduct(hull.Peek(), top, sortedPoints[i]) <= 0)
{
top = hull.Pop();
}
hull.Push(top);
hull.Push(sortedPoints[i]);
}
// 转换栈为列表
List<Vector2> convexHull = new List<Vector2>(hull);
List<Vector3> returnV3=new List<Vector3>();
foreach (Vector2 v2 in convexHull)
{
// 获取点的屏幕坐标
Vector2 screenPoint = UI.Camera.ScreenToWorldPoint(v2);
returnV3.Add(screenPoint);
}
return returnV3;
}
// 计算叉积
static float CrossProduct(Vector2 a, Vector2 b, Vector2 c)
{
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}