/// <summary> /// Find the intersection of an existing segment and a segment that is being /// inserted. Insert a vertex at the intersection, splitting an existing subsegment. /// </summary> /// <param name="splittri"></param> /// <param name="splitsubseg"></param> /// <param name="endpoint2"></param> /// <remarks> /// The segment being inserted connects the apex of splittri to endpoint2. /// splitsubseg is the subsegment being split, and MUST adjoin splittri. /// Hence, endpoints of the subsegment being split are the origin and /// destination of splittri. /// On completion, splittri is a handle having the newly inserted /// intersection point as its origin, and endpoint1 as its destination. /// </remarks> private void SegmentIntersection(ref Otri splittri, ref Osub splitsubseg, Vertex endpoint2) { Osub opposubseg = default(Osub); Vertex endpoint1; Vertex torg, tdest; Vertex leftvertex, rightvertex; Vertex newvertex; InsertVertexResult success; var dummysub = mesh.dummysub; double ex, ey; double tx, ty; double etx, ety; double split, denom; // Find the other three segment endpoints. endpoint1 = splittri.Apex(); torg = splittri.Org(); tdest = splittri.Dest(); // Segment intersection formulae; see the Antonio reference. tx = tdest.X - torg.X; ty = tdest.Y - torg.Y; ex = endpoint2.X - endpoint1.X; ey = endpoint2.Y - endpoint1.Y; etx = torg.X - endpoint2.X; ety = torg.Y - endpoint2.Y; denom = ty * ex - tx * ey; if (denom == 0.0) { throw new Exception("Attempt to find intersection of parallel segments."); } split = (ey * etx - ex * ety) / denom; // Create the new vertex. newvertex = new Vertex( torg.X + split * (tdest.X - torg.X), torg.Y + split * (tdest.Y - torg.Y), splitsubseg.seg.boundary); newvertex.Id = mesh.hash_vtx++; mesh.vertices.Add(newvertex.Id, newvertex); // Insert the intersection vertex. This should always succeed. success = mesh.InsertVertex(newvertex, ref splittri, ref splitsubseg, false, false); if (success != InsertVertexResult.Successful) { throw new Exception("Failure to split a segment."); } // Record a triangle whose origin is the new vertex. newvertex.tri = splittri; if (mesh.steinerleft > 0) { mesh.steinerleft--; } // Divide the segment into two, and correct the segment endpoints. splitsubseg.Sym(); splitsubseg.Pivot(ref opposubseg); splitsubseg.Dissolve(dummysub); opposubseg.Dissolve(dummysub); do { splitsubseg.SetSegOrg(newvertex); splitsubseg.Next(); } while (splitsubseg.seg.hash != Mesh.DUMMY); do { opposubseg.SetSegOrg(newvertex); opposubseg.Next(); } while (opposubseg.seg.hash != Mesh.DUMMY); // Inserting the vertex may have caused edge flips. We wish to rediscover // the edge connecting endpoint1 to the new intersection vertex. FindDirection(ref splittri, endpoint1); rightvertex = splittri.Dest(); leftvertex = splittri.Apex(); if ((leftvertex.X == endpoint1.X) && (leftvertex.Y == endpoint1.Y)) { splittri.Onext(); } else if ((rightvertex.X != endpoint1.X) || (rightvertex.Y != endpoint1.Y)) { throw new Exception("Topological inconsistency after splitting a segment."); } // 'splittri' should have destination endpoint1. }