/// <summary> /// 检查vertices中索引为current的顶点是否为耳朵. /// </summary> static bool CheckIsEar(ArrayLinkedList<EarVertex> vertices, int current) { if (vertices.Count < 3) { return false; } int prev = vertices.PrevIndex(current); int next = vertices.NextIndex(current); Vector3[] points = new Vector3[] { vertices[prev].vertex.Position, vertices[current].vertex.Position, vertices[next].vertex.Position }; // 三点共线, 必然不是耳朵. if (MathUtility.Approximately(points[0].cross2(points[2], points[1]), 0f)) { return false; } // 检查prev, current, next组成的三角形, 是否包含其它点. for (var e = vertices.GetEnumerator(); e.MoveNext(); ) { if (e.CurrentIndex == current || e.CurrentIndex == prev || e.CurrentIndex == next) { continue; } if (MathUtility.PolygonContains(points, vertices[e.CurrentIndex].vertex.Position)) { return false; } } // 如果不包含其它点, 那么该点为耳朵. return true; }
/// <summary> /// 对vertices组成的多边形三角形化. /// <para>earTips为当前的耳朵的索引.</para> static List<Vertex> DoTriangulate(ArrayLinkedList<EarVertex> vertices, ArrayLinkedList<int> earTips) { // N边行, 形成N-2个三角形, 共3*(N-2)个顶点. List<Vertex> answer = new List<Vertex>((vertices.Count - 2) * 3); // 被移除的耳朵. EarVertex[] removedEars = new EarVertex[2]; int removedEarCount = 0; // 需要被移除的耳朵的在earTips中的索引. int earTipIndex = -1; for (var e = earTips.GetEnumerator(); e.MoveNext(); ) { if (earTipIndex >= 0) { earTips.RemoveAt(earTipIndex); } earTipIndex = e.CurrentIndex; // 需要移除的耳朵的在vertices中的索引. int earTipVertexIndex = earTips[earTipIndex]; // 需要移除的耳朵节点. EarVertex earTipVertex = vertices[earTipVertexIndex]; // 耳朵节点的上一个节点. int prevIndex = vertices.PrevIndex(earTipVertexIndex); EarVertex prevVertex = vertices.PrevValue(earTipVertexIndex); // 耳朵节点的下一个节点. int nextIndex = vertices.NextIndex(earTipVertexIndex); EarVertex nextVertex = vertices.NextValue(earTipVertexIndex); // 构成新的三角形. answer.Add(prevVertex.vertex); answer.Add(earTipVertex.vertex); answer.Add(nextVertex.vertex); // 以该节点为耳尖的耳朵已被"切掉", 移除这个节点. vertices.RemoveAt(earTipVertexIndex); // 更新该节点的上节点的状态. int state = UpdateEarVertexState(vertices, prevIndex); // 加入新的耳朵. if (state > 0) { prevVertex.earListIndex = earTips.Add(prevIndex); } // 收集之前是, 而现在不再是耳朵的节点. else if (state < 0) { removedEars[removedEarCount++] = prevVertex; } // 更新该节点的下节点的状态. state = UpdateEarVertexState(vertices, nextIndex); if (state > 0) { nextVertex.earListIndex = earTips.Add(nextIndex); } else if (state < 0) { removedEars[removedEarCount++] = nextVertex; } // 在earTips中移除之前是, 现在不是耳朵的节点. for (int i = 0; i < removedEarCount; ++i) { Utility.Verify(removedEars[i].earListIndex >= 0); earTips.RemoveAt(removedEars[i].earListIndex); removedEars[i].earListIndex = -1; } removedEarCount = 0; } // 移除最后一个耳朵, 清空earTips. if (earTipIndex >= 0) { earTips.RemoveAt(earTipIndex); } return answer; }