/// <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; 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) { logger.Error("Attempt to find intersection of parallel segments.", "Mesh.SegmentIntersection()"); 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, this.nextras); newvertex.hash = this.hash_vtx++; newvertex.id = newvertex.hash; // Interpolate its attributes. for (int i = 0; i < nextras; i++) { newvertex.attributes[i] = torg.attributes[i] + split * (tdest.attributes[i] - torg.attributes[i]); } vertices.Add(newvertex.hash, newvertex); // Insert the intersection vertex. This should always succeed. success = InsertVertex(newvertex, ref splittri, ref splitsubseg, false, false); if (success != InsertVertexResult.Successful) { logger.Error("Failure to split a segment.", "Mesh.SegmentIntersection()"); throw new Exception("Failure to split a segment."); } // Record a triangle whose origin is the new vertex. newvertex.tri = splittri; if (steinerleft > 0) { steinerleft--; } // Divide the segment into two, and correct the segment endpoints. splitsubseg.SymSelf(); splitsubseg.Pivot(ref opposubseg); splitsubseg.Dissolve(); opposubseg.Dissolve(); do { splitsubseg.SetSegOrg(newvertex); splitsubseg.NextSelf(); } while (splitsubseg.seg != Mesh.dummysub); do { opposubseg.SetSegOrg(newvertex); opposubseg.NextSelf(); } while (opposubseg.seg != Mesh.dummysub); // 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.OnextSelf(); } else if ((rightvertex.x != endpoint1.x) || (rightvertex.y != endpoint1.y)) { logger.Error("Topological inconsistency after splitting a segment.", "Mesh.SegmentIntersection()"); throw new Exception("Topological inconsistency after splitting a segment."); } // 'splittri' should have destination endpoint1. }