private TriangulatedSet Triangulate(int _beginId, int _endId, int _depth) { // Number of points in this set int size = _endId - _beginId + 1; if (size == 2) // Segment { HalfEdge h = CreateHalfEdge(_beginId, _endId); return(new TriangulatedSet(h.twin, h.twin)); } else if (size == 3) // Triangle { HalfEdge hA = CreateHalfEdge(_beginId, _beginId + 1); HalfEdge hB = CreateHalfEdge(_beginId + 1, _endId); ConnectHalfedges(hA, hB); // A,B,C are in CCW, which means A,B,C are inner halfedges if (IsCcw(m_vertice[_beginId], m_vertice[_beginId + 1], m_vertice[_endId])) { // DONOT delete this line since it update other connection infomation HalfEdge hC = BridgeHalfedges(hB, hA); return(new TriangulatedSet(hA.twin, hB.twin)); } // A,B,C are in CW, which means A,B,C are outer halfedges else if (IsCcw(m_vertice[_beginId], m_vertice[_endId], m_vertice[_beginId + 1])) { HalfEdge hC = BridgeHalfedges(hB, hA); return(new TriangulatedSet(hC, hC)); } else { return(new TriangulatedSet(hA.twin, hB.twin)); } } else // size >= 4, Separate { // Recursively delaunay triangulate L and R halves TriangulatedSet leftSet = Triangulate(_beginId, _beginId + (size / 2) - 1, _depth + 1); TriangulatedSet rightSet = Triangulate(_beginId + (size / 2), _endId, _depth + 1); HalfEdge LLh = leftSet.leftHalfedge; HalfEdge LRh = leftSet.rightHalfedge; HalfEdge RLh = rightSet.leftHalfedge; HalfEdge RRh = rightSet.rightHalfedge; // Compute the lowest common tangent of L and R while (true) { if (IsLeftOf(RLh.DstId, LRh)) { LRh = LRh.next; } else if (IsLeftOf(LRh.orgId, RLh)) { RLh = RLh.Prev; } else { break; } } HalfEdge baseH = BridgeHalfedges(RLh, LRh); if (LRh.orgId == LLh.DstId) { LLh = baseH; } if (RLh.DstId == RRh.orgId) { RRh = baseH; } // Merge while (true) { // Locate the first L point (Lcand.Org) to be encountered by the rising bubble // and delete L edges that fail the circle test HalfEdge Lcand = baseH.twin.Prev; if (IsLeftOf(Lcand.orgId, baseH.twin)) { while (IsInCircle( baseH.DstId, baseH.orgId, Lcand.orgId, Lcand.twin.Prev.orgId)) { HalfEdge nextLcand = Lcand.twin.Prev; DeleteHalfedge(Lcand); Lcand = nextLcand; } } HalfEdge Rcand = baseH.twin.next; if (IsLeftOf(Rcand.DstId, baseH.twin)) { while (IsInCircle( baseH.DstId, baseH.orgId, Rcand.DstId, Rcand.twin.next.DstId)) { HalfEdge nextRcand = Rcand.twin.next; DeleteHalfedge(Rcand); Rcand = nextRcand; } } // If both Lcand and Rcand are invalid, then baseH is the upper common tangent if (IsLeftOf(Lcand.orgId, baseH.twin) == false && IsLeftOf(Rcand.DstId, baseH.twin) == false) { break; } // The next cross halfedge is to be connected to either Lcand.Org or rcand.Dst // if both are valid, then choose the appropriate one using the inCircle test if (IsLeftOf(Lcand.orgId, baseH.twin) && IsInCircle(Lcand.orgId, baseH.DstId, baseH.orgId, Rcand.DstId) == false) { baseH = BridgeHalfedges(baseH.twin, Lcand); } else { baseH = BridgeHalfedges(Rcand, baseH.twin); } } return(new TriangulatedSet(LLh, RRh)); } }
/// <summary> /// Exclusive right /// </summary> /// <param name="_vId"></param> /// <param name="_h"></param> /// <returns></returns> private bool IsRightOf(int _vId, HalfEdge _h) { return(!IsNotCw(m_vertice[_vId], m_vertice[_h.orgId], m_vertice[_h.DstId])); }
/// <summary> /// Exclusive left /// </summary> /// <param name="_vId"></param> /// <param name="_h"></param> /// <returns></returns> private bool IsLeftOf(int _vId, HalfEdge _h) { return(IsCcw(m_vertice[_vId], m_vertice[_h.orgId], m_vertice[_h.DstId])); }
/// <summary> /// _hB should always be the isolated one to detach, _hA should be the base one. /// _hB\ \ /// \ \ /// _hA ---- --- /// </summary> /// <param name="_hA"></param> /// <param name="_hB"></param> private void DisconnectHalfedges(HalfEdge _hA, HalfEdge _hB) { _hA.next = _hB.twin.next; _hB.twin.next = _hB; }
/// <summary> /// Make halfedge A's head connect to halfedge B's rear /// </summary> /// <param name="_hA"></param> /// <param name="_hB"></param> private void ConnectHalfedges(HalfEdge _hA, HalfEdge _hB) { _hB.Prev.next = _hA.next; _hA.next = _hB; }
public TriangulatedSet(HalfEdge _lh, HalfEdge _rh) { leftHalfedge = _lh; rightHalfedge = _rh; }