/// <summary> /// 检查所给点集是否为顺时针排序(向量叉乘的法线朝向) /// </summary> /// <returns></returns> public static bool CheckVector(List <Vector3> points) { // 创建一个除去自身的 多边形,判断是否为内点(凹点) List <Vector3> polygon = new List <Vector3>(points); polygon.RemoveAt(0); Vector3 vector3_1 = points[0] - points[1]; Vector3 vector3_2 = points[points.Count - 1] - points[0]; Vector3 nom = Vector3.Cross(vector3_1, vector3_2); // 算出法线方向。Unity为左手坐标系, 使用左手定则 //是否是凹点 if (Math2d.IsPointInsidePolygon(points[0], polygon)) { // 法线方向朝下。即逆时针排序,需要反转 if (nom.y < 0) { return(false); } } else // 凸点 { // 法线方向朝上。即逆时针排序,需要反转 if (nom.y > 0) { return(false); } } return(true); }
/// <summary> /// 返回三角形的内部(整数)顶点 /// </summary> /// <param name="trianglePoints">三角形的三个顶点</param> /// <returns></returns> public static List <Vector3> GetPointsInTriangle(List <Vector3> trianglePoints) { // 取出所围的四边形 float xMin = Mathf.Min(Mathf.Min(trianglePoints[0].x, trianglePoints[1].x), trianglePoints[2].x); float zMax = Mathf.Max(Mathf.Max(trianglePoints[0].z, trianglePoints[1].z), trianglePoints[2].z); float zMin = Mathf.Min(Mathf.Min(trianglePoints[0].z, trianglePoints[1].z), trianglePoints[2].z); List <Vector3> InsidePoints = new List <Vector3>(); // 内部点集 Vector3 pointTmp = Vector3.zero; // 临时点 List <Vector3> crossPoints = new List <Vector3>(); // 交点点集(2个点) // 遍历四边形的内部所有点 for (int z = (int)zMin, iLength = (int)zMax + 1; z < iLength; z++) { pointTmp.Set(xMin, 0, z); // 设置临时点(固定x,将z递增) Math2d.IsPointInsidePolygon(pointTmp, trianglePoints.ToArray(), out crossPoints); // 获取z轴平行线与三角形的交点 // 循环添加两个交点之间的网格点 for (int x = (int)crossPoints[0].x, length = (int)crossPoints[crossPoints.Count - 1].x + 1; x < length; x++) { InsidePoints.Add(new Vector3(x, 0, z)); } } return(InsidePoints); }
/// <summary> /// 获取两点组成的矩形边框 /// </summary> /// <param name="start">起始点</param> /// <param name="end">终止点</param> /// <param name="width">宽度</param> /// <returns></returns> public static Vector2[] GetRect(Vector2 start, Vector2 end, float width) { Vector2[] rect = new Vector2[4]; Vector2 dir = Math2d.GetHorizontalDir(end - start); rect[0] = start + dir * width; rect[1] = start - dir * width; rect[2] = end + dir * width; rect[3] = end - dir * width; return(rect); }
/// <summary> /// 通过给定网格间隔,获取三角形内部的网格点 /// </summary> /// <param name="trianglePoints">三角形顶点</param> /// <param name="pieceX">X的间隔</param> /// <param name="pieceZ">Z的间隔</param> /// <returns></returns> public static List <Vector3> GetPointsInTriangle(Vector3[] trianglePoints, float pieceX, float pieceZ) { float halfX = 0.5f * pieceX; float halfZ = 0.5f * pieceZ; // 归置三角形顶点 for (int i = 0; i < trianglePoints.Length; i++) { trianglePoints[i].x = trianglePoints[i].x - trianglePoints[i].x % pieceX + halfX; trianglePoints[i].z = trianglePoints[i].z - trianglePoints[i].z % pieceZ + halfZ; } // 取出所围的四边形 float xMin = Mathf.Min(trianglePoints[0].x, trianglePoints[1].x, trianglePoints[2].x); xMin = xMin - xMin % pieceX - halfX; // 取到所在的网格中心点 float zMax = Mathf.Max(trianglePoints[0].z, trianglePoints[1].z, trianglePoints[2].z); zMax = zMax + zMax % pieceZ + halfZ; float zMin = Mathf.Min(trianglePoints[0].z, trianglePoints[1].z, trianglePoints[2].z); zMin = zMin - zMin % pieceZ - halfZ; List <Vector3> InsidePoints = new List <Vector3>(); // 内部点集 Vector3 pointTmp = Vector3.zero; // 临时点 List <Vector3> crossPoints = new List <Vector3>(); // 交点点集(2个点) // 遍历四边形的内部所有点 for (float z = zMin; z <= zMax; z += pieceZ) { pointTmp.Set(xMin, 0, z); // 设置临时点(固定x,将z递增) Math2d.IsPointInsidePolygon(pointTmp, trianglePoints, out crossPoints); // 获取z轴平行线与三角形的交点 if (crossPoints.Count == 2) { // 循环添加两个交点之间的网格中心点 for (float x = Mathf.Min(crossPoints[0].x, crossPoints[1].x); x <= Mathf.Max(crossPoints[0].x, crossPoints[1].x); x += pieceX) { InsidePoints.Add(new Vector3(x, 0, z)); } } crossPoints.Clear(); } return(InsidePoints); }
/// <summary> /// 将一个多边形转化为多个三角形 /// </summary> /// <param name="points"></param> /// <returns></returns> public static List <Vector2[]> PolygonToTriangles(List <Vector2> points) { if (points.Count < 3) { return(null); } List <Vector2[]> triangles = new List <Vector2[]>(); int index = points.Count - 1; int next; int prev; while (points.Count > 3) { List <Vector2> polygon = new List <Vector2>(points); polygon.RemoveAt(index); //是否是凹点 if (!Math2d.IsPointInsidePolygon(points[index], polygon.ToArray(), false)) { // 是否是可划分顶点:新的多边形没有顶点在分割的三角形内 if (IsFragementIndex(points, index, false)) { //可划分,剖分三角形 next = (index == points.Count - 1) ? 0 : index + 1; prev = (index == 0) ? points.Count - 1 : index - 1; triangles.Add(new Vector2[] { points[index], points[prev], points[next] }); points.RemoveAt(index); index = (index + points.Count - 1) % points.Count; // 防止出现index超出值域 continue; } } index = (index + 1) % points.Count; } triangles.Add(new Vector2[] { points[1], points[0], points[2] }); return(triangles); }
/// <summary> /// 获取扇形区域的点集合(包括圆心点)没有地平线以下的区域 /// </summary> /// <param name="origin">圆心点</param> /// <param name="tarPoint"></param> /// <param name="alpha">x,z轴张角</param> /// <param name="theta">x,y轴张角</param> /// <returns></returns> public static Vector3[] GetSectorPoints_2(Vector3 origin, Vector3 tarPoint, float alpha, float theta) { List <Vector3> points = new List <Vector3>(); int halfAlpha = (int)(alpha / 2); Vector3 startVector_1 = tarPoint - origin; // 获取底面中间向量 float tempHeight = Mathf.Tan(theta * Mathf.Deg2Rad) * startVector_1.magnitude; // 扇形区域最边缘高度 // 获取扇形下表面和下表面的半径 float radiusDown = (tarPoint - origin).magnitude; float radiusUp = radiusDown / Mathf.Cos(theta * Mathf.Deg2Rad); // 获得扇形顶面半径 // 获取扇形弧边所有点的方向向量 List <Vector3> dirsDown = new List <Vector3>(); List <Vector3> dirsUp = new List <Vector3>(); for (int i = -halfAlpha, j = 0; i <= halfAlpha; i += 3, j++) { // 获取下弧边的方向向量 Vector2 temp = Math2d.GetTargetVector(new Vector2(startVector_1.x, startVector_1.z), i); dirsDown.Add(new Vector3(temp.x, 0, temp.y)); // 获取上弧边的方向向量 Vector3 targetDir = temp.magnitude / Mathf.Cos(i * Mathf.Deg2Rad) * dirsDown[j].normalized + Vector3.up * tempHeight; dirsUp.Add(targetDir); } // 获取扇形所有点 points.Add(origin); for (int i = 0; i < dirsDown.Count; i++) { points.Add(dirsDown[i].normalized * radiusDown + origin); } points.Add(origin); for (int i = 0; i < dirsUp.Count; i++) { points.Add(dirsUp[i].normalized * radiusUp + origin); } return(points.ToArray()); }
/// <summary> /// 以index点和前后两个点构造一个三角形,判断点集内的其余点是否全部在这个三角形外部(忽略y轴) /// </summary> public static bool IsFragementIndex(List <Vector3> verts, int index, bool containEdge = true) { int len = verts.Count; List <Vector3> triangleVert = new List <Vector3>(); int next = (index == len - 1) ? 0 : index + 1; int prev = (index == 0) ? len - 1 : index - 1; triangleVert.Add(verts[prev]); triangleVert.Add(verts[index]); triangleVert.Add(verts[next]); for (int i = 0; i < len; i++) { if (i != index && i != prev && i != next) { if (Math2d.IsPointInsidePolygon(verts[i], triangleVert.ToArray(), containEdge)) { return(false); } } } return(true); }