/// <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. }
SplayNode FrontLocate(SplayNode splayroot, Otri bottommost, Vertex searchvertex, ref Otri searchtri, ref bool farright) { bool farrightflag; bottommost.Copy(ref searchtri); splayroot = Splay(splayroot, searchvertex, ref searchtri); farrightflag = false; while (!farrightflag && RightOfHyperbola(ref searchtri, searchvertex)) { searchtri.OnextSelf(); farrightflag = searchtri.Equal(bottommost); } farright = farrightflag; return splayroot; }
/// <summary> /// Find the first triangle on the path from one point to another. /// </summary> /// <param name="searchtri"></param> /// <param name="searchpoint"></param> /// <returns> /// The return value notes whether the destination or apex of the found /// triangle is collinear with the two points in question.</returns> /// <remarks> /// Finds the triangle that intersects a line segment drawn from the /// origin of 'searchtri' to the point 'searchpoint', and returns the result /// in 'searchtri'. The origin of 'searchtri' does not change, even though /// the triangle returned may differ from the one passed in. This routine /// is used to find the direction to move in to get from one point to /// another. /// </remarks> private FindDirectionResult FindDirection(ref Otri searchtri, Vertex searchpoint) { Otri checktri = default(Otri); Vertex startvertex; Vertex leftvertex, rightvertex; double leftccw, rightccw; bool leftflag, rightflag; startvertex = searchtri.Org(); rightvertex = searchtri.Dest(); leftvertex = searchtri.Apex(); // Is 'searchpoint' to the left? leftccw = Primitives.CounterClockwise(searchpoint, startvertex, leftvertex); leftflag = leftccw > 0.0; // Is 'searchpoint' to the right? rightccw = Primitives.CounterClockwise(startvertex, searchpoint, rightvertex); rightflag = rightccw > 0.0; if (leftflag && rightflag) { // 'searchtri' faces directly away from 'searchpoint'. We could go left // or right. Ask whether it's a triangle or a boundary on the left. searchtri.Onext(ref checktri); if (checktri.triangle == Mesh.dummytri) { leftflag = false; } else { rightflag = false; } } while (leftflag) { // Turn left until satisfied. searchtri.OnextSelf(); if (searchtri.triangle == Mesh.dummytri) { logger.Error("Unable to find a triangle on path.", "Mesh.FindDirection().1"); throw new Exception("Unable to find a triangle on path."); } leftvertex = searchtri.Apex(); rightccw = leftccw; leftccw = Primitives.CounterClockwise(searchpoint, startvertex, leftvertex); leftflag = leftccw > 0.0; } while (rightflag) { // Turn right until satisfied. searchtri.OprevSelf(); if (searchtri.triangle == Mesh.dummytri) { logger.Error("Unable to find a triangle on path.", "Mesh.FindDirection().2"); throw new Exception("Unable to find a triangle on path."); } rightvertex = searchtri.Dest(); leftccw = rightccw; rightccw = Primitives.CounterClockwise(startvertex, searchpoint, rightvertex); rightflag = rightccw > 0.0; } if (leftccw == 0.0) { return FindDirectionResult.Leftcollinear; } else if (rightccw == 0.0) { return FindDirectionResult.Rightcollinear; } else { return FindDirectionResult.Within; } }