1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
| using System.Collections.Generic; using UnityEngine; public class Polygon { NodeList m_NodeList; List<int> m_Triangles = new List<int>(); public Polygon(List<Vector3> vertices) { if (vertices.Count <= 2) { throw new System.InvalidOperationException("非多边形"); } m_NodeList = new NodeList(vertices); } public int[] SimpleTriangulation() { SimpleCutPolygon(); return m_Triangles.ToArray(); } public int[] Triangulation() { while (m_NodeList.GetCount >= 3) { if (!CutPolygon()) { throw new System.InvalidOperationException("点位非逆时针排布或围成图形非简单多边形"); } } return m_Triangles.ToArray(); } private void SimpleCutPolygon() { int nodeListCount = m_NodeList.GetCount; for (int i = 0; i < nodeListCount - 1; i++) { Node currentNode = m_NodeList.GetNodeByIdx(i); Node nextNode = currentNode.NextNode; Node oppositeNode = m_NodeList.GetNodeByIdx(nodeListCount - 1 - i); if (i < nodeListCount / 2 - 1 || i > nodeListCount / 2 - 1) { m_Triangles.Add(oppositeNode.Index); m_Triangles.Add(nextNode.Index); m_Triangles.Add(currentNode.Index); } } } private bool CutPolygon() { List<Node> raisedVertices = new List<Node>(); List<Node> concaveVertices = new List<Node>(); List<Node> earTips = new List<Node>(); for (int i = 0; i < m_NodeList.GetCount; i++) { Node currentNode = m_NodeList.GetNodeByIdx(i); Node previousNode = currentNode.PreviousNode; Node nextNode = currentNode.NextNode; if (IsRaisedVertex(previousNode, currentNode, nextNode)) { raisedVertices.Add(currentNode); if (IsEarTip(previousNode, currentNode, nextNode)) { earTips.Add(currentNode); } } else { concaveVertices.Add(currentNode); } } if (earTips.Count == 0) { return false; } m_Triangles.Add(earTips[0].PreviousNode.Index); m_Triangles.Add(earTips[0].NextNode.Index); m_Triangles.Add(earTips[0].Index); m_NodeList.RemoveNode(earTips[0]); return true; } private bool IsRaisedVertex(Node previousNode, Node currentNode, Node nextNode) { Vector3 side1 = currentNode.Position - previousNode.Position; Vector3 side2 = nextNode.Position - currentNode.Position; Vector3 crossRes = Vector3.Cross(side1, side2); if (crossRes.y > 0) { return false; } else { return true; } } private bool IsEarTip(Node previousNode, Node currentNode, Node nextNode) { bool flag = true; for (int i = 0; i < m_NodeList.GetCount; i++) { Node node = m_NodeList.GetNodeByIdx(i); if (node != currentNode && node != previousNode && node != nextNode) { if (InTrigon(node.Position, previousNode.Position, currentNode.Position, nextNode.Position)) { flag = false; break; } } } return flag; } private bool InTrigon(Vector3 p, Vector3 a, Vector3 b, Vector3 c) { Vector3 pa = a - p; Vector3 pb = b - p; Vector3 pc = c - p; Vector3 pab = Vector3.Cross(pa, pb); Vector3 pbc = Vector3.Cross(pb, pc); Vector3 pca = Vector3.Cross(pc, pa); float d1 = Vector3.Dot(pab, pbc); float d2 = Vector3.Dot(pab, pca); float d3 = Vector3.Dot(pbc, pca); bool result = Mathf.Sign(d1) == Mathf.Sign(d2) && Mathf.Sign(d2) == Mathf.Sign(d3) && Mathf.Sign(d1) == Mathf.Sign(d3); return result; } private class Node { public int Index { get; set; } public Vector3 Position { get; set; } public Node PreviousNode { get; set; } public Node NextNode { get; set; } public Node(int idx, Vector3 position) { Index = idx; Position = position; } } private class NodeList { List<Node> list = new List<Node>(); public NodeList(List<Vector3> vertices) { int verticesCount = vertices.Count; for (int i = 0; i < verticesCount; i++) { Node node = new Node(i, vertices[i]); list.Add(node); } for (int i = 0; i < verticesCount; i++) { int previousIdx; int nextIdx; if (i == 0) { previousIdx = verticesCount - 1; nextIdx = i + 1; } else if (i == verticesCount - 1) { previousIdx = i - 1; nextIdx = 0; } else { previousIdx = i - 1; nextIdx = i + 1; } list[i].PreviousNode = list[previousIdx]; list[i].NextNode = list[nextIdx]; } } public int GetCount { get { return list.Count; } } public Node GetNodeByIdx(int idx) { return list[idx]; } public void RemoveNode(Node node) { node.NextNode.PreviousNode = node.PreviousNode; node.PreviousNode.NextNode = node.NextNode; list.Remove(node); } } }
|