/// <summary> /// Test a triangle for quality and size. /// </summary> /// <param name="testtri">Triangle to check.</param> /// <remarks> /// Tests a triangle to see if it satisfies the minimum angle condition and /// the maximum area condition. Triangles that aren't up to spec are added /// to the bad triangle queue. /// </remarks> public void TestTriangle(ref Otri testtri) { Otri tri1 = default(Otri), tri2 = default(Otri); Osub testsub = default(Osub); Vertex torg, tdest, tapex; Vertex base1, base2; Vertex org1, dest1, org2, dest2; Vertex joinvertex; double dxod, dyod, dxda, dyda, dxao, dyao; double dxod2, dyod2, dxda2, dyda2, dxao2, dyao2; double apexlen, orglen, destlen, minedge; double angle; double area; double dist1, dist2; double maxangle; torg = testtri.Org(); tdest = testtri.Dest(); tapex = testtri.Apex(); dxod = torg.x - tdest.x; dyod = torg.y - tdest.y; dxda = tdest.x - tapex.x; dyda = tdest.y - tapex.y; dxao = tapex.x - torg.x; dyao = tapex.y - torg.y; dxod2 = dxod * dxod; dyod2 = dyod * dyod; dxda2 = dxda * dxda; dyda2 = dyda * dyda; dxao2 = dxao * dxao; dyao2 = dyao * dyao; // Find the lengths of the triangle's three edges. apexlen = dxod2 + dyod2; orglen = dxda2 + dyda2; destlen = dxao2 + dyao2; if ((apexlen < orglen) && (apexlen < destlen)) { // The edge opposite the apex is shortest. minedge = apexlen; // Find the square of the cosine of the angle at the apex. angle = dxda * dxao + dyda * dyao; angle = angle * angle / (orglen * destlen); base1 = torg; base2 = tdest; testtri.Copy(ref tri1); } else if (orglen < destlen) { // The edge opposite the origin is shortest. minedge = orglen; // Find the square of the cosine of the angle at the origin. angle = dxod * dxao + dyod * dyao; angle = angle * angle / (apexlen * destlen); base1 = tdest; base2 = tapex; testtri.Lnext(ref tri1); } else { // The edge opposite the destination is shortest. minedge = destlen; // Find the square of the cosine of the angle at the destination. angle = dxod * dxda + dyod * dyda; angle = angle * angle / (apexlen * orglen); base1 = tapex; base2 = torg; testtri.Lprev(ref tri1); } if (behavior.VarArea || behavior.fixedArea || (behavior.UserTest != null)) { // Check whether the area is larger than permitted. area = 0.5 * (dxod * dyda - dyod * dxda); if (behavior.fixedArea && (area > behavior.MaxArea)) { // Add this triangle to the list of bad triangles. queue.Enqueue(ref testtri, minedge, tapex, torg, tdest); return; } // Nonpositive area constraints are treated as unconstrained. if ((behavior.VarArea) && (area > testtri.tri.area) && (testtri.tri.area > 0.0)) { // Add this triangle to the list of bad triangles. queue.Enqueue(ref testtri, minedge, tapex, torg, tdest); return; } // Check whether the user thinks this triangle is too large. if ((behavior.UserTest != null) && behavior.UserTest(testtri.tri, area)) { queue.Enqueue(ref testtri, minedge, tapex, torg, tdest); return; } } // find the maximum edge and accordingly the pqr orientation if ((apexlen > orglen) && (apexlen > destlen)) { // The edge opposite the apex is longest. // maxedge = apexlen; // Find the cosine of the angle at the apex. maxangle = (orglen + destlen - apexlen) / (2 * Math.Sqrt(orglen * destlen)); } else if (orglen > destlen) { // The edge opposite the origin is longest. // maxedge = orglen; // Find the cosine of the angle at the origin. maxangle = (apexlen + destlen - orglen) / (2 * Math.Sqrt(apexlen * destlen)); } else { // The edge opposite the destination is longest. // maxedge = destlen; // Find the cosine of the angle at the destination. maxangle = (apexlen + orglen - destlen) / (2 * Math.Sqrt(apexlen * orglen)); } // Check whether the angle is smaller than permitted. if ((angle > behavior.goodAngle) || (maxangle < behavior.maxGoodAngle && behavior.MaxAngle != 0.0)) { // Use the rules of Miller, Pav, and Walkington to decide that certain // triangles should not be split, even if they have bad angles. // A skinny triangle is not split if its shortest edge subtends a // small input angle, and both endpoints of the edge lie on a // concentric circular shell. For convenience, I make a small // adjustment to that rule: I check if the endpoints of the edge // both lie in segment interiors, equidistant from the apex where // the two segments meet. // First, check if both points lie in segment interiors. if ((base1.type == VertexType.SegmentVertex) && (base2.type == VertexType.SegmentVertex)) { // Check if both points lie in a common segment. If they do, the // skinny triangle is enqueued to be split as usual. tri1.Pivot(ref testsub); if (testsub.seg.hash == Mesh.DUMMY) { // No common segment. Find a subsegment that contains 'torg'. tri1.Copy(ref tri2); do { tri1.Oprev(); tri1.Pivot(ref testsub); } while (testsub.seg.hash == Mesh.DUMMY); // Find the endpoints of the containing segment. org1 = testsub.SegOrg(); dest1 = testsub.SegDest(); // Find a subsegment that contains 'tdest'. do { tri2.Dnext(); tri2.Pivot(ref testsub); } while (testsub.seg.hash == Mesh.DUMMY); // Find the endpoints of the containing segment. org2 = testsub.SegOrg(); dest2 = testsub.SegDest(); // Check if the two containing segments have an endpoint in common. joinvertex = null; if ((dest1.x == org2.x) && (dest1.y == org2.y)) { joinvertex = dest1; } else if ((org1.x == dest2.x) && (org1.y == dest2.y)) { joinvertex = org1; } if (joinvertex != null) { // Compute the distance from the common endpoint (of the two // segments) to each of the endpoints of the shortest edge. dist1 = ((base1.x - joinvertex.x) * (base1.x - joinvertex.x) + (base1.y - joinvertex.y) * (base1.y - joinvertex.y)); dist2 = ((base2.x - joinvertex.x) * (base2.x - joinvertex.x) + (base2.y - joinvertex.y) * (base2.y - joinvertex.y)); // If the two distances are equal, don't split the triangle. if ((dist1 < 1.001 * dist2) && (dist1 > 0.999 * dist2)) { // Return now to avoid enqueueing the bad triangle. return; } } } } // Add this triangle to the list of bad triangles. queue.Enqueue(ref testtri, minedge, tapex, torg, tdest); } }
private void ConstructBoundaryBvdCell(Vertex vertex) { VoronoiRegion region = new VoronoiRegion(vertex); regions.Add(region); Otri f = default(Otri); Otri f_init = default(Otri); Otri f_next = default(Otri); Otri f_prev = default(Otri); Osub sf = default(Osub); Osub sfn = default(Osub); Vertex torg, tdest, tapex, sorg, sdest; Point cc_f, cc_f_next, p; int n = mesh.triangles.Count; // Call P the polygon (cell) in construction List <Point> vpoints = new List <Point>(); // Call f_init a triangle incident to x vertex.tri.Copy(ref f_init); if (f_init.Org() != vertex) { throw new Exception("ConstructBoundaryBvdCell: inconsistent topology."); } // Let f be initialized to f_init f_init.Copy(ref f); // Call f_next the next triangle counterclockwise around x f_init.Onext(ref f_next); f_init.Oprev(ref f_prev); // Is the border to the left? if (f_prev.triangle != Mesh.dummytri) { // Go clockwise until we reach the border (or the initial triangle) while (f_prev.triangle != Mesh.dummytri && !f_prev.Equal(f_init)) { f_prev.Copy(ref f); f_prev.OprevSelf(); } f.Copy(ref f_init); f.Onext(ref f_next); } if (f_prev.triangle == Mesh.dummytri) { // For vertices on the domain boundaray, add the vertex. For // internal boundaries don't add it. p = new Point(vertex.x, vertex.y); p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); } // Add midpoint of start triangles' edge. torg = f.Org(); tdest = f.Dest(); p = new Point((torg.X + tdest.X) / 2, (torg.Y + tdest.Y) / 2); p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); // repeat ... until f = f_init do { // Call Lffnext the line going through the circumcenters of f and f_next cc_f = this.points[f.triangle.id]; if (f_next.triangle == Mesh.dummytri) { if (!f.triangle.infected) { // Add last circumcenter vpoints.Add(cc_f); } // Add midpoint of last triangles' edge (chances are it has already // been added, so post process cell to remove duplicates???) torg = f.Org(); tapex = f.Apex(); p = new Point((torg.X + tapex.X) / 2, (torg.Y + tapex.Y) / 2); p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); break; } cc_f_next = this.points[f_next.triangle.id]; // if f is tagged non-blind then if (!f.triangle.infected) { // Insert the circumcenter of f into P vpoints.Add(cc_f); if (f_next.triangle.infected) { // Call S_fnext the constrained edge blinding f_next sfn.seg = subsegMap[f_next.triangle.hash]; // Insert point Lf,f_next /\ Sf_next into P if (SegmentsIntersect(sfn.SegOrg(), sfn.SegDest(), cc_f, cc_f_next, out p, true)) { p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); } } } else { // Call Sf the constrained edge blinding f sf.seg = subsegMap[f.triangle.hash]; sorg = sf.SegOrg(); sdest = sf.SegDest(); // if f_next is tagged non-blind then if (!f_next.triangle.infected) { tdest = f.Dest(); tapex = f.Apex(); // Both circumcenters lie on the blinded side, but we // have to add the intersection with the segment. // Center of f edge dest->apex Point bisec = new Point((tdest.X + tapex.X) / 2, (tdest.Y + tapex.Y) / 2); // Find intersection of seg with line through f's bisector and circumcenter if (SegmentsIntersect(sorg, sdest, bisec, cc_f, out p, false)) { p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); } // Insert point Lf,f_next /\ Sf into P if (SegmentsIntersect(sorg, sdest, cc_f, cc_f_next, out p, true)) { p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); } } else { // Call Sf_next the constrained edge blinding f_next sfn.seg = subsegMap[f_next.triangle.hash]; // if Sf != Sf_next then if (!sf.Equal(sfn)) { // Insert Lf,fnext /\ Sf and Lf,fnext /\ Sfnext into P if (SegmentsIntersect(sorg, sdest, cc_f, cc_f_next, out p, true)) { p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); } if (SegmentsIntersect(sfn.SegOrg(), sfn.SegDest(), cc_f, cc_f_next, out p, true)) { p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); } } else { // Both circumcenters lie on the blinded side, but we // have to add the intersection with the segment. // Center of f_next edge org->dest Point bisec = new Point((torg.X + tdest.X) / 2, (torg.Y + tdest.Y) / 2); // Find intersection of seg with line through f_next's bisector and circumcenter if (SegmentsIntersect(sorg, sdest, bisec, cc_f_next, out p, false)) { p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); } } } } // f <- f_next f_next.Copy(ref f); // Call f_next the next triangle counterclockwise around x f_next.OnextSelf(); }while (!f.Equal(f_init)); // Output: Bounded Voronoi cell of x in counterclockwise order. region.Add(vpoints); }
private void ConstructBvdCell(Vertex vertex) { VoronoiRegion region = new VoronoiRegion(vertex); regions.Add(region); Otri f = default(Otri); Otri f_init = default(Otri); Otri f_next = default(Otri); Osub sf = default(Osub); Osub sfn = default(Osub); Point cc_f, cc_f_next, p; int n = mesh.triangles.Count; // Call P the polygon (cell) in construction List <Point> vpoints = new List <Point>(); // Call f_init a triangle incident to x vertex.tri.Copy(ref f_init); if (f_init.Org() != vertex) { throw new Exception("ConstructBvdCell: inconsistent topology."); } // Let f be initialized to f_init f_init.Copy(ref f); // Call f_next the next triangle counterclockwise around x f_init.Onext(ref f_next); // repeat ... until f = f_init do { // Call Lffnext the line going through the circumcenters of f and f_next cc_f = this.points[f.triangle.id]; cc_f_next = this.points[f_next.triangle.id]; // if f is tagged non-blind then if (!f.triangle.infected) { // Insert the circumcenter of f into P vpoints.Add(cc_f); if (f_next.triangle.infected) { // Call S_fnext the constrained edge blinding f_next sfn.seg = subsegMap[f_next.triangle.hash]; // Insert point Lf,f_next /\ Sf_next into P if (SegmentsIntersect(sfn.SegOrg(), sfn.SegDest(), cc_f, cc_f_next, out p, true)) { p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); } } } else { // Call Sf the constrained edge blinding f sf.seg = subsegMap[f.triangle.hash]; // if f_next is tagged non-blind then if (!f_next.triangle.infected) { // Insert point Lf,f_next /\ Sf into P if (SegmentsIntersect(sf.SegOrg(), sf.SegDest(), cc_f, cc_f_next, out p, true)) { p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); } } else { // Call Sf_next the constrained edge blinding f_next sfn.seg = subsegMap[f_next.triangle.hash]; // if Sf != Sf_next then if (!sf.Equal(sfn)) { // Insert Lf,fnext /\ Sf and Lf,fnext /\ Sfnext into P if (SegmentsIntersect(sf.SegOrg(), sf.SegDest(), cc_f, cc_f_next, out p, true)) { p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); } if (SegmentsIntersect(sfn.SegOrg(), sfn.SegDest(), cc_f, cc_f_next, out p, true)) { p.id = n + segIndex; points[n + segIndex] = p; segIndex++; vpoints.Add(p); } } } } // f <- f_next f_next.Copy(ref f); // Call f_next the next triangle counterclockwise around x f_next.OnextSelf(); }while (!f.Equal(f_init)); // Output: Bounded Voronoi cell of x in counterclockwise order. region.Add(vpoints); }
private void ConstructBoundaryBvdCell(Vertex vertex) { Vertex vertex1; Point point; VoronoiRegion voronoiRegion = new VoronoiRegion(vertex); this.regions.Add(voronoiRegion); Otri otri = new Otri(); Otri otri1 = new Otri(); Otri otri2 = new Otri(); Otri otri3 = new Otri(); Osub item = new Osub(); Osub osub = new Osub(); int count = this.mesh.triangles.Count; List <Point> points = new List <Point>(); vertex.tri.Copy(ref otri1); if (otri1.Org() != vertex) { throw new Exception("ConstructBoundaryBvdCell: inconsistent topology."); } otri1.Copy(ref otri); otri1.Onext(ref otri2); otri1.Oprev(ref otri3); if (otri3.triangle != Mesh.dummytri) { while (otri3.triangle != Mesh.dummytri && !otri3.Equal(otri1)) { otri3.Copy(ref otri); otri3.OprevSelf(); } otri.Copy(ref otri1); otri.Onext(ref otri2); } if (otri3.triangle == Mesh.dummytri) { point = new Point(vertex.x, vertex.y) { id = count + this.segIndex }; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); } Vertex vertex2 = otri.Org(); Vertex vertex3 = otri.Dest(); point = new Point((vertex2.X + vertex3.X) / 2, (vertex2.Y + vertex3.Y) / 2) { id = count + this.segIndex }; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); do { Point point1 = this.points[otri.triangle.id]; if (otri2.triangle != Mesh.dummytri) { Point point2 = this.points[otri2.triangle.id]; if (otri.triangle.infected) { item.seg = this.subsegMap[otri.triangle.hash]; Vertex vertex4 = item.SegOrg(); Vertex vertex5 = item.SegDest(); if (otri2.triangle.infected) { osub.seg = this.subsegMap[otri2.triangle.hash]; if (!item.Equal(osub)) { if (this.SegmentsIntersect(vertex4, vertex5, point1, point2, out point, true)) { point.id = count + this.segIndex; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); } if (this.SegmentsIntersect(osub.SegOrg(), osub.SegDest(), point1, point2, out point, true)) { point.id = count + this.segIndex; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); } } else if (this.SegmentsIntersect(vertex4, vertex5, new Point((vertex2.X + vertex3.X) / 2, (vertex2.Y + vertex3.Y) / 2), point2, out point, false)) { point.id = count + this.segIndex; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); } } else { vertex3 = otri.Dest(); vertex1 = otri.Apex(); if (this.SegmentsIntersect(vertex4, vertex5, new Point((vertex3.X + vertex1.X) / 2, (vertex3.Y + vertex1.Y) / 2), point1, out point, false)) { point.id = count + this.segIndex; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); } if (this.SegmentsIntersect(vertex4, vertex5, point1, point2, out point, true)) { point.id = count + this.segIndex; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); } } } else { points.Add(point1); if (otri2.triangle.infected) { osub.seg = this.subsegMap[otri2.triangle.hash]; if (this.SegmentsIntersect(osub.SegOrg(), osub.SegDest(), point1, point2, out point, true)) { point.id = count + this.segIndex; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); } } } otri2.Copy(ref otri); otri2.OnextSelf(); } else { if (!otri.triangle.infected) { points.Add(point1); } vertex2 = otri.Org(); vertex1 = otri.Apex(); point = new Point((vertex2.X + vertex1.X) / 2, (vertex2.Y + vertex1.Y) / 2) { id = count + this.segIndex }; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); break; } }while (!otri.Equal(otri1)); voronoiRegion.Add(points); }
private void ConstructBvdCell(Vertex vertex) { Point point; VoronoiRegion voronoiRegion = new VoronoiRegion(vertex); this.regions.Add(voronoiRegion); Otri otri = new Otri(); Otri otri1 = new Otri(); Otri otri2 = new Otri(); Osub item = new Osub(); Osub osub = new Osub(); int count = this.mesh.triangles.Count; List <Point> points = new List <Point>(); vertex.tri.Copy(ref otri1); if (otri1.Org() != vertex) { throw new Exception("ConstructBvdCell: inconsistent topology."); } otri1.Copy(ref otri); otri1.Onext(ref otri2); do { Point point1 = this.points[otri.triangle.id]; Point point2 = this.points[otri2.triangle.id]; if (otri.triangle.infected) { item.seg = this.subsegMap[otri.triangle.hash]; if (otri2.triangle.infected) { osub.seg = this.subsegMap[otri2.triangle.hash]; if (!item.Equal(osub)) { if (this.SegmentsIntersect(item.SegOrg(), item.SegDest(), point1, point2, out point, true)) { point.id = count + this.segIndex; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); } if (this.SegmentsIntersect(osub.SegOrg(), osub.SegDest(), point1, point2, out point, true)) { point.id = count + this.segIndex; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); } } } else if (this.SegmentsIntersect(item.SegOrg(), item.SegDest(), point1, point2, out point, true)) { point.id = count + this.segIndex; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); } } else { points.Add(point1); if (otri2.triangle.infected) { osub.seg = this.subsegMap[otri2.triangle.hash]; if (this.SegmentsIntersect(osub.SegOrg(), osub.SegDest(), point1, point2, out point, true)) { point.id = count + this.segIndex; this.points[count + this.segIndex] = point; this.segIndex = this.segIndex + 1; points.Add(point); } } } otri2.Copy(ref otri); otri2.OnextSelf(); }while (!otri.Equal(otri1)); voronoiRegion.Add(points); }
public void TestTriangle(ref Otri testtri) { Vertex vertex; Vertex vertex1; double num; double num1; double num2; Otri otri = new Otri(); Otri otri1 = new Otri(); Osub osub = new Osub(); Vertex vertex2 = testtri.Org(); Vertex vertex3 = testtri.Dest(); Vertex vertex4 = testtri.Apex(); double num3 = vertex2.x - vertex3.x; double num4 = vertex2.y - vertex3.y; double num5 = vertex3.x - vertex4.x; double num6 = vertex3.y - vertex4.y; double num7 = vertex4.x - vertex2.x; double num8 = vertex4.y - vertex2.y; double num9 = num3 * num3; double num10 = num4 * num4; double num11 = num5 * num5; double num12 = num6 * num6; double num13 = num8 * num8; double num14 = num9 + num10; double num15 = num11 + num12; double num16 = num7 * num7 + num13; if (num14 < num15 && num14 < num16) { num = num14; num1 = num5 * num7 + num6 * num8; num1 = num1 * num1 / (num15 * num16); vertex = vertex2; vertex1 = vertex3; testtri.Copy(ref otri); } else if (num15 >= num16) { num = num16; num1 = num3 * num5 + num4 * num6; num1 = num1 * num1 / (num14 * num15); vertex = vertex4; vertex1 = vertex2; testtri.Lprev(ref otri); } else { num = num15; num1 = num3 * num7 + num4 * num8; num1 = num1 * num1 / (num14 * num16); vertex = vertex3; vertex1 = vertex4; testtri.Lnext(ref otri); } if (this.behavior.VarArea || this.behavior.fixedArea || this.behavior.Usertest) { double num17 = 0.5 * (num3 * num6 - num4 * num5); if (this.behavior.fixedArea && num17 > this.behavior.MaxArea) { this.queue.Enqueue(ref testtri, num, vertex4, vertex2, vertex3); return; } if (this.behavior.VarArea && num17 > testtri.triangle.area && testtri.triangle.area > 0) { this.queue.Enqueue(ref testtri, num, vertex4, vertex2, vertex3); return; } if (this.behavior.Usertest && this.userTest != null && this.userTest(vertex2, vertex3, vertex4, num17)) { this.queue.Enqueue(ref testtri, num, vertex4, vertex2, vertex3); return; } } if (num14 <= num15 || num14 <= num16) { num2 = (num15 <= num16 ? (num14 + num15 - num16) / (2 * Math.Sqrt(num14 * num15)) : (num14 + num16 - num15) / (2 * Math.Sqrt(num14 * num16))); } else { num2 = (num15 + num16 - num14) / (2 * Math.Sqrt(num15 * num16)); } if (num1 > this.behavior.goodAngle || num2 < this.behavior.maxGoodAngle && this.behavior.MaxAngle != 0) { if (vertex.type == VertexType.SegmentVertex && vertex1.type == VertexType.SegmentVertex) { otri.SegPivot(ref osub); if (osub.seg == Mesh.dummysub) { otri.Copy(ref otri1); do { otri.OprevSelf(); otri.SegPivot(ref osub); }while (osub.seg == Mesh.dummysub); Vertex vertex5 = osub.SegOrg(); Vertex vertex6 = osub.SegDest(); do { otri1.DnextSelf(); otri1.SegPivot(ref osub); }while (osub.seg == Mesh.dummysub); Vertex vertex7 = osub.SegOrg(); Vertex vertex8 = osub.SegDest(); Vertex vertex9 = null; if (vertex6.x == vertex7.x && vertex6.y == vertex7.y) { vertex9 = vertex6; } else if (vertex5.x == vertex8.x && vertex5.y == vertex8.y) { vertex9 = vertex5; } if (vertex9 != null) { double num18 = (vertex.x - vertex9.x) * (vertex.x - vertex9.x) + (vertex.y - vertex9.y) * (vertex.y - vertex9.y); double num19 = (vertex1.x - vertex9.x) * (vertex1.x - vertex9.x) + (vertex1.y - vertex9.y) * (vertex1.y - vertex9.y); if (num18 < 1.001 * num19 && num18 > 0.999 * num19) { return; } } } } this.queue.Enqueue(ref testtri, num, vertex4, vertex2, vertex3); } }