public void TestDprev() { var triangles = CreateExampleMesh(); Otri t = default; // Start with the top triangle. t.tri = triangles[3]; // Start with edge 5 -> 3. t.orient = 2; // Make sure we're on the correct edge. Assert.AreEqual(5, t.Org().ID); Assert.AreEqual(3, t.Dest().ID); t.Dprev(); Assert.AreEqual(4, t.Org().ID); Assert.AreEqual(3, t.Dest().ID); Assert.AreEqual(1, t.tri.ID); t.Dprev(); Assert.AreEqual(1, t.Org().ID); Assert.AreEqual(3, t.Dest().ID); Assert.AreEqual(0, t.tri.ID); // Out of mesh. t.Dprev(); Assert.AreEqual(-1, t.tri.ID); }
public void TestOnext() { var triangles = CreateExampleMesh(); Otri t = default; // Start with the bottom right triangle. t.tri = triangles[2]; // Start with edge 1 -> 2. t.orient = 0; // Make sure we're on the correct edge. Assert.AreEqual(1, t.Org().ID); Assert.AreEqual(2, t.Dest().ID); t.Onext(); Assert.AreEqual(1, t.Org().ID); Assert.AreEqual(4, t.Dest().ID); Assert.AreEqual(1, t.tri.ID); t.Onext(); Assert.AreEqual(1, t.Org().ID); Assert.AreEqual(3, t.Dest().ID); Assert.AreEqual(0, t.tri.ID); // Out of mesh. t.Onext(); Assert.AreEqual(-1, t.tri.ID); }
public void TestRprev() { var triangles = CreateExampleMesh(); Otri t = default; // Start with the top triangle. t.tri = triangles[3]; // Start with edge 3 -> 4. t.orient = 0; // Make sure we're on the correct edge. Assert.AreEqual(3, t.Org().ID); Assert.AreEqual(4, t.Dest().ID); t.Rprev(); Assert.AreEqual(4, t.Org().ID); Assert.AreEqual(1, t.Dest().ID); Assert.AreEqual(2, t.tri.ID); t.Rprev(); Assert.AreEqual(1, t.Org().ID); Assert.AreEqual(3, t.Dest().ID); Assert.AreEqual(0, t.tri.ID); // Back where we started. t.Rprev(); Assert.AreEqual(3, t.tri.ID); }
public void TestRnext() { var triangles = CreateExampleMesh(); Otri t = default; // Start with the bottom left triangle. t.tri = triangles[0]; // Start with edge 1 -> 3. t.orient = 1; // Make sure we're on the correct edge. Assert.AreEqual(1, t.Org().ID); Assert.AreEqual(3, t.Dest().ID); t.Rnext(); Assert.AreEqual(4, t.Org().ID); Assert.AreEqual(1, t.Dest().ID); Assert.AreEqual(2, t.tri.ID); t.Rnext(); Assert.AreEqual(3, t.Org().ID); Assert.AreEqual(4, t.Dest().ID); Assert.AreEqual(3, t.tri.ID); // Back where we started. t.Rnext(); Assert.AreEqual(0, t.tri.ID); }
public void TestDest() { Otri t = default; t.tri = Helper.CreateTriangle(0, vertices[1], vertices[4], vertices[3]); t.orient = 0; Assert.AreEqual(4, t.Dest().ID); t.orient = 1; Assert.AreEqual(3, t.Dest().ID); t.orient = 2; Assert.AreEqual(1, t.Dest().ID); }
/// <summary> /// Check if given triangle is blinded by given segment. /// </summary> /// <param name="tri">Triangle.</param> /// <param name="seg">Segments</param> /// <returns>Returns true, if the triangle is blinded.</returns> private bool TriangleIsBlinded(ref Otri tri, ref Osub seg) { Point c, pt; Vertex torg = tri.Org(); Vertex tdest = tri.Dest(); Vertex tapex = tri.Apex(); Vertex sorg = seg.Org(); Vertex sdest = seg.Dest(); c = points[tri.tri.id]; if (SegmentsIntersect(sorg, sdest, c, torg, out pt, true)) { return(true); } if (SegmentsIntersect(sorg, sdest, c, tdest, out pt, true)) { return(true); } if (SegmentsIntersect(sorg, sdest, c, tapex, out pt, true)) { return(true); } return(false); }
/// <summary> /// Enumerate all edges of the given mesh. /// </summary> /// <param name="mesh"></param> /// <returns></returns> public IEnumerable <Edge> EnumerateEdges(IMesh mesh) { Otri tri = default; Otri neighbor = default; Osub sub = default; Vertex p1, p2; foreach (var t in mesh.Triangles) { tri.tri = t; tri.orient = 0; for (int i = 0; i < 3; i++) { tri.Sym(ref neighbor); int nid = neighbor.tri.id; if ((tri.tri.id < nid) || (nid == Mesh.DUMMY)) { p1 = tri.Org(); p2 = tri.Dest(); tri.Pivot(ref sub); // Boundary mark of dummysub is 0, so we don't need to worry about that. yield return(new Edge(p1.id, p2.id, sub.seg.boundary)); } tri.orient++; } } }
/// <summary> /// Compute the Voronoi vertices (the circumcenters of the triangles). /// </summary> /// <returns>An empty map, which will map all vertices to a list of leaving edges.</returns> protected List <HalfEdge>[] ComputeVertices(Mesh mesh, Vertex[] vertices) { Otri tri = default(Otri); double xi = 0, eta = 0; Vertex vertex; Point pt; int id; // Maps all vertices to a list of leaving edges. var map = new List <HalfEdge> [mesh.triangles.Count]; // Compue triangle circumcenters foreach (var t in mesh.triangles) { id = t.id; tri.tri = t; pt = predicates.FindCircumcenter(tri.Org(), tri.Dest(), tri.Apex(), ref xi, ref eta); vertex = factory.CreateVertex(pt.x, pt.y); vertex.id = id; vertices[id] = vertex; map[id] = new List <HalfEdge>(); } return(map); }
/// <summary> /// Virally infect all of the triangles of the convex hull that are not /// protected by subsegments. Where there are subsegments, set boundary /// markers as appropriate. /// </summary> private void InfectHull() { Otri hulltri = default(Otri); Otri nexttri = default(Otri); Otri starttri = default(Otri); Osub hullsubseg = default(Osub); Vertex horg, hdest; // Find a triangle handle on the hull. hulltri.triangle = Mesh.dummytri; hulltri.orient = 0; hulltri.SymSelf(); // Remember where we started so we know when to stop. hulltri.Copy(ref starttri); // Go once counterclockwise around the convex hull. do { // Ignore triangles that are already infected. if (!hulltri.IsInfected()) { // Is the triangle protected by a subsegment? hulltri.SegPivot(ref hullsubseg); if (hullsubseg.seg == Mesh.dummysub) { // The triangle is not protected; infect it. if (!hulltri.IsInfected()) { hulltri.Infect(); viri.Add(hulltri.triangle); } } else { // The triangle is protected; set boundary markers if appropriate. if (hullsubseg.seg.boundary == 0) { hullsubseg.seg.boundary = 1; horg = hulltri.Org(); hdest = hulltri.Dest(); if (horg.mark == 0) { horg.mark = 1; } if (hdest.mark == 0) { hdest.mark = 1; } } } } // To find the next hull edge, go clockwise around the next vertex. hulltri.LnextSelf(); hulltri.Oprev(ref nexttri); while (nexttri.triangle != Mesh.dummytri) { nexttri.Copy(ref hulltri); hulltri.Oprev(ref nexttri); } } while (!hulltri.Equal(starttri)); }
private SweepLine.SplayNode SplayInsert(SweepLine.SplayNode splayroot, Otri newkey, Point searchpoint) { SweepLine.SplayNode splayNode = new SweepLine.SplayNode(); this.splaynodes.Add(splayNode); newkey.Copy(ref splayNode.keyedge); splayNode.keydest = newkey.Dest(); if (splayroot == null) { splayNode.lchild = null; splayNode.rchild = null; } else if (!this.RightOfHyperbola(ref splayroot.keyedge, searchpoint)) { splayNode.lchild = splayroot.lchild; splayNode.rchild = splayroot; splayroot.lchild = null; } else { splayNode.lchild = splayroot; splayNode.rchild = splayroot.rchild; splayroot.rchild = null; } return(splayNode); }
SplayNode SplayInsert(SplayNode splayroot, Otri newkey, Point searchpoint) { SplayNode newsplaynode; newsplaynode = new SplayNode(); //poolalloc(m.splaynodes); splaynodes.Add(newsplaynode); newkey.Copy(ref newsplaynode.keyedge); newsplaynode.keydest = newkey.Dest(); if (splayroot == null) { newsplaynode.lchild = null; newsplaynode.rchild = null; } else if (RightOfHyperbola(ref splayroot.keyedge, searchpoint)) { newsplaynode.lchild = splayroot; newsplaynode.rchild = splayroot.rchild; splayroot.rchild = null; } else { newsplaynode.lchild = splayroot.lchild; newsplaynode.rchild = splayroot; splayroot.lchild = null; } return(newsplaynode); }
private bool RightOfHyperbola(ref Otri fronttri, Point newsite) { Vertex leftvertex, rightvertex; double dxa, dya, dxb, dyb; leftvertex = fronttri.Dest(); rightvertex = fronttri.Apex(); if ((leftvertex.Y < rightvertex.Y) || ((leftvertex.Y == rightvertex.Y) && (leftvertex.X < rightvertex.X))) { if (newsite.X >= rightvertex.X) { return(true); } } else { if (newsite.X <= leftvertex.X) { return(false); } } dxa = leftvertex.X - newsite.X; dya = leftvertex.Y - newsite.Y; dxb = rightvertex.X - newsite.X; dyb = rightvertex.Y - newsite.Y; return(dya * (dxb * dxb + dyb * dyb) > dyb * (dxa * dxa + dya * dya)); }
public static void WriteElements(Mesh mesh, string filename) { Otri otri = new Otri(); bool flag = mesh.behavior.useRegions; int num = 0; otri.orient = 0; using (StreamWriter streamWriter = new StreamWriter(new FileStream(filename, FileMode.Create))) { streamWriter.WriteLine("{0} 3 {1}", mesh.triangles.Count, (flag ? 1 : 0)); foreach (Triangle value in mesh.triangles.Values) { otri.triangle = value; Vertex vertex = otri.Org(); Vertex vertex1 = otri.Dest(); Vertex vertex2 = otri.Apex(); streamWriter.Write("{0} {1} {2} {3}", new object[] { num, vertex.id, vertex1.id, vertex2.id }); if (flag) { streamWriter.Write(" {0}", otri.triangle.region); } streamWriter.WriteLine(); int num1 = num; num = num1 + 1; value.id = num1; } } }
bool RightOfHyperbola(ref Otri fronttri, Point newsite) { Vertex leftvertex, rightvertex; double dxa, dya, dxb, dyb; Statistic.HyperbolaCount++; leftvertex = fronttri.Dest(); rightvertex = fronttri.Apex(); if ((leftvertex.y < rightvertex.y) || ((leftvertex.y == rightvertex.y) && (leftvertex.x < rightvertex.x))) { if (newsite.x >= rightvertex.x) { return(true); } } else { if (newsite.x <= leftvertex.x) { return(false); } } dxa = leftvertex.x - newsite.x; dya = leftvertex.y - newsite.y; dxb = rightvertex.x - newsite.x; dyb = rightvertex.y - newsite.y; return(dya * (dxb * dxb + dyb * dyb) > dyb * (dxa * dxa + dya * dya)); }
/// <summary> /// Find the holes and infect them. Find the area constraints and infect /// them. Infect the convex hull. Spread the infection and kill triangles. /// Spread the area constraints. /// </summary> public void CarveHoles() { Otri searchtri = default(Otri); Vertex searchorg, searchdest; LocateResult intersect; var dummytri = mesh.dummytri; if (!mesh.behavior.Convex) { // Mark as infected any unprotected triangles on the boundary. // This is one way by which concavities are created. InfectHull(); } if (!mesh.behavior.NoHoles) { // Infect each triangle in which a hole lies. foreach (var hole in mesh.holes) { // Ignore holes that aren't within the bounds of the mesh. if (mesh.bounds.Contains(hole)) { // Start searching from some triangle on the outer boundary. searchtri.tri = dummytri; searchtri.orient = 0; searchtri.Sym(); // Ensure that the hole is to the left of this boundary edge; // otherwise, locate() will falsely report that the hole // falls within the starting triangle. searchorg = searchtri.Org(); searchdest = searchtri.Dest(); if (RobustPredicates.CounterClockwise(searchorg, searchdest, hole) > 0.0) { // Find a triangle that contains the hole. intersect = mesh.locator.Locate(hole, ref searchtri); if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected())) { // Infect the triangle. This is done by marking the triangle // as infected and including the triangle in the virus pool. searchtri.Infect(); viri.Add(searchtri.tri); } } } } } if (viri.Count > 0) { // Carve the holes and concavities. Plague(); } // Free up memory (virus pool should be empty anyway). viri.Clear(); }
/// <summary> /// Scout the first triangle on the path from one endpoint to another, and check /// for completion (reaching the second endpoint), a collinear vertex, or the /// intersection of two segments. /// </summary> /// <param name="searchtri"></param> /// <param name="endpoint2"></param> /// <param name="newmark"></param> /// <returns> /// Returns true if the entire segment is successfully inserted, and false /// if the job must be finished by ConstrainedEdge(). /// </returns> /// <remarks> /// If the first triangle on the path has the second endpoint as its /// destination or apex, a subsegment is inserted and the job is done. /// If the first triangle on the path has a destination or apex that lies on /// the segment, a subsegment is inserted connecting the first endpoint to /// the collinear vertex, and the search is continued from the collinear /// vertex. /// If the first triangle on the path has a subsegment opposite its origin, /// then there is a segment that intersects the segment being inserted. /// Their intersection vertex is inserted, splitting the subsegment. /// </remarks> private bool ScoutSegment(ref Otri searchtri, Vertex endpoint2, ushort newmark) { Otri crosstri = default(Otri); Osub crosssubseg = default(Osub); Vertex leftvertex, rightvertex; FindDirectionResult collinear; collinear = FindDirection(ref searchtri, endpoint2); rightvertex = searchtri.Dest(); leftvertex = searchtri.Apex(); if (((leftvertex.X == endpoint2.X) && (leftvertex.Y == endpoint2.Y)) || ((rightvertex.X == endpoint2.X) && (rightvertex.Y == endpoint2.Y))) { // The segment is already an edge in the mesh. if ((leftvertex.X == endpoint2.X) && (leftvertex.Y == endpoint2.Y)) { searchtri.Lprev(); } // Insert a subsegment, if there isn't already one there. mesh.InsertSubseg(ref searchtri, newmark); return(true); } if (collinear == FindDirectionResult.Leftcollinear) { // We've collided with a vertex between the segment's endpoints. // Make the collinear vertex be the triangle's origin. searchtri.Lprev(); mesh.InsertSubseg(ref searchtri, newmark); // Insert the remainder of the segment. return(ScoutSegment(ref searchtri, endpoint2, newmark)); } if (collinear == FindDirectionResult.Rightcollinear) { // We've collided with a vertex between the segment's endpoints. mesh.InsertSubseg(ref searchtri, newmark); // Make the collinear vertex be the triangle's origin. searchtri.Lnext(); // Insert the remainder of the segment. return(ScoutSegment(ref searchtri, endpoint2, newmark)); } searchtri.Lnext(ref crosstri); crosstri.Pivot(ref crosssubseg); // Check for a crossing segment. if (crosssubseg.seg.hash == Mesh.DUMMY) { return(false); } // Insert a vertex at the intersection. SegmentIntersection(ref crosstri, ref crosssubseg, endpoint2); crosstri.Copy(ref searchtri); mesh.InsertSubseg(ref searchtri, newmark); // Insert the remainder of the segment. return(ScoutSegment(ref searchtri, endpoint2, newmark)); }
public void TestDissolve() { // Outer space triangle. var dummy = new Triangle() { id = -1 }; var triangles = CreateExampleMesh(); Otri s = default; Otri t = default; Otri tmp = default; // The bottom left triangle with edge 1 -> 3. s.tri = triangles[0]; s.orient = 1; // The center triangle with edge 3 -> 1. t.tri = triangles[1]; t.orient = 2; // Make sure we're on the correct edges. Assert.AreEqual(1, s.Org().ID); Assert.AreEqual(3, s.Dest().ID); Assert.AreEqual(3, t.Org().ID); Assert.AreEqual(1, t.Dest().ID); // Check that neighbors are properly set. s.Sym(ref tmp); Assert.AreEqual(1, tmp.tri.ID); t.Sym(ref tmp); Assert.AreEqual(0, tmp.tri.ID); // Now dissolve the bond from one side. s.Dissolve(dummy); // Check neighbors. s.Sym(ref tmp); Assert.AreEqual(-1, tmp.tri.ID); t.Sym(ref tmp); Assert.AreEqual(0, tmp.tri.ID); // And dissolve the bond from the other side. t.Dissolve(dummy); // Check neighbors. s.Sym(ref tmp); Assert.AreEqual(-1, tmp.tri.ID); t.Sym(ref tmp); Assert.AreEqual(-1, tmp.tri.ID); }
public static void WriteEdges(Mesh mesh, string filename) { Otri otri = new Otri(); Otri otri1 = new Otri(); Osub osub = new Osub(); Behavior behavior = mesh.behavior; using (StreamWriter streamWriter = new StreamWriter(new FileStream(filename, FileMode.Create))) { streamWriter.WriteLine("{0} {1}", mesh.edges, (behavior.UseBoundaryMarkers ? "1" : "0")); long num = (long)0; foreach (Triangle value in mesh.triangles.Values) { otri.triangle = value; otri.orient = 0; while (otri.orient < 3) { otri.Sym(ref otri1); if (otri.triangle.id < otri1.triangle.id || otri1.triangle == Mesh.dummytri) { Vertex vertex = otri.Org(); Vertex vertex1 = otri.Dest(); if (!behavior.UseBoundaryMarkers) { streamWriter.WriteLine("{0} {1} {2}", num, vertex.id, vertex1.id); } else if (!behavior.useSegments) { StreamWriter streamWriter1 = streamWriter; object[] objArray = new object[] { num, vertex.id, vertex1.id, null }; objArray[3] = (otri1.triangle == Mesh.dummytri ? "1" : "0"); streamWriter1.WriteLine("{0} {1} {2} {3}", objArray); } else { otri.SegPivot(ref osub); if (osub.seg != Mesh.dummysub) { streamWriter.WriteLine("{0} {1} {2} {3}", new object[] { num, vertex.id, vertex1.id, osub.seg.boundary }); } else { streamWriter.WriteLine("{0} {1} {2} {3}", new object[] { num, vertex.id, vertex1.id, 0 }); } } num = num + (long)1; } otri.orient = otri.orient + 1; } } } }
public void Update(Otri otri) { if (otri.Triangle == null || otri.Triangle.ID < 0) { renderer.SelectTriangle(null, null, null); } else { renderer.SelectTriangle(otri.Triangle, otri.Org(), otri.Dest()); } this.Render(); }
private void ComputeCircumCenters() { Otri otri = new Otri(); double num = 0; double num1 = 0; foreach (Triangle value in this.mesh.triangles.Values) { otri.triangle = value; Point point = Primitives.FindCircumcenter(otri.Org(), otri.Dest(), otri.Apex(), ref num, ref num1); point.id = value.id; this.points[value.id] = point; } }
private void InfectHull() { Otri otri = new Otri(); Otri otri1 = new Otri(); Otri otri2 = new Otri(); Osub osub = new Osub(); otri.triangle = Mesh.dummytri; otri.orient = 0; otri.SymSelf(); otri.Copy(ref otri2); do { if (!otri.IsInfected()) { otri.SegPivot(ref osub); if (osub.seg == Mesh.dummysub) { if (!otri.IsInfected()) { otri.Infect(); this.viri.Add(otri.triangle); } } else if (osub.seg.boundary == 0) { osub.seg.boundary = 1; Vertex vertex = otri.Org(); Vertex vertex1 = otri.Dest(); if (vertex.mark == 0) { vertex.mark = 1; } if (vertex1.mark == 0) { vertex1.mark = 1; } } } otri.LnextSelf(); otri.Oprev(ref otri1); while (otri1.triangle != Mesh.dummytri) { otri1.Copy(ref otri); otri.Oprev(ref otri1); } }while (!otri.Equal(otri2)); }
private void ComputeCircumCenters() { Otri tri = default(Otri); float xi = 0, eta = 0; Point pt; // Compue triangle circumcenters foreach (var item in _TriangleNetMesh.triangles) { tri.tri = item; pt = predicates.FindCircumcenter(tri.Org(), tri.Dest(), tri.Apex(), ref xi, ref eta); pt.id = item.id; points[item.id] = pt; } }
private void ComputeCircumCenters() { Otri tri = default(Otri); double xi = 0, eta = 0; Point pt; // Compue triangle circumcenters foreach (var item in mesh.triangles.Values) { tri.triangle = item; pt = Primitives.FindCircumcenter(tri.Org(), tri.Dest(), tri.Apex(), ref xi, ref eta); pt.id = item.id; points[item.id] = pt; } }
public bool CheckDelaunay() { Otri otri = new Otri(); Otri otri1 = new Otri(); Osub osub = new Osub(); bool noExact = Behavior.NoExact; Behavior.NoExact = false; int num = 0; foreach (Triangle value in this.mesh.triangles.Values) { otri.triangle = value; otri.orient = 0; while (otri.orient < 3) { Vertex vertex = otri.Org(); Vertex vertex1 = otri.Dest(); Vertex vertex2 = otri.Apex(); otri.Sym(ref otri1); Vertex vertex3 = otri1.Apex(); bool flag = (otri1.triangle == Mesh.dummytri || Otri.IsDead(otri1.triangle) || otri.triangle.id >= otri1.triangle.id || !(vertex != this.mesh.infvertex1) || !(vertex != this.mesh.infvertex2) || !(vertex != this.mesh.infvertex3) || !(vertex1 != this.mesh.infvertex1) || !(vertex1 != this.mesh.infvertex2) || !(vertex1 != this.mesh.infvertex3) || !(vertex2 != this.mesh.infvertex1) || !(vertex2 != this.mesh.infvertex2) || !(vertex2 != this.mesh.infvertex3) || !(vertex3 != this.mesh.infvertex1) || !(vertex3 != this.mesh.infvertex2) ? false : vertex3 != this.mesh.infvertex3); if (this.mesh.checksegments & flag) { otri.SegPivot(ref osub); if (osub.seg != Mesh.dummysub) { flag = false; } } if (flag && Primitives.NonRegular(vertex, vertex1, vertex2, vertex3) > 0) { this.logger.Warning(string.Format("Non-regular pair of triangles found (IDs {0}/{1}).", otri.triangle.id, otri1.triangle.id), "Quality.CheckDelaunay()"); num++; } otri.orient = otri.orient + 1; } } if (num == 0) { this.logger.Info("Mesh is Delaunay."); } Behavior.NoExact = noExact; return(num == 0); }
private void ComputeCircumCenters() { Otri otri = new Otri(); double num = 0; double num1 = 0; foreach (Triangle value in this.mesh.triangles.Values) { otri.triangle = value; Point point = Primitives.FindCircumcenter(otri.Org(), otri.Dest(), otri.Apex(), ref num, ref num1); point.id = value.id; this.points[value.id] = point; this.bounds.Update(point.x, point.y); } double num2 = Math.Max(this.bounds.Width, this.bounds.Height); this.bounds.Scale(num2, num2); }
/// <summary> /// Write the triangles to an .ele file. /// </summary> /// <param name="mesh"></param> /// <param name="filename"></param> public void WriteElements(Mesh mesh, string filename) { Otri tri = default(Otri); Vertex p1, p2, p3; bool regions = mesh.behavior.useRegions; int j = 0; tri.orient = 0; using ( #if NETFX_CORE var writer = new WinRTLegacy.IO.StreamWriter(filename) #else var writer = new StreamWriter(filename) #endif ) { // Number of triangles, vertices per triangle, attributes per triangle. writer.WriteLine("{0} 3 {1}", mesh.triangles.Count, regions ? 1 : 0); foreach (var item in mesh.triangles) { tri.tri = item; p1 = tri.Org(); p2 = tri.Dest(); p3 = tri.Apex(); // Triangle number, indices for three vertices. writer.Write("{0} {1} {2} {3}", j, p1.id, p2.id, p3.id); if (regions) { writer.Write(" {0}", tri.tri.label); } writer.WriteLine(); // Number elements item.id = j++; } } }
/// <summary> /// Enumerate all edges of the given mesh. /// </summary> /// <param name="mesh"></param> /// <param name="skipSegments"></param> /// <returns></returns> /// <remarks> /// In contrast to <see cref="EnumerateEdges(IMesh)"/> this method will return /// objects that include the vertex information (and not only the indices). /// </remarks> public static IEnumerable <ISegment> EnumerateEdges(IMesh mesh, bool skipSegments = true) { Otri tri = default; Otri neighbor = default; Osub sub = default; Vertex p1, p2; bool segments = !skipSegments; foreach (var t in mesh.Triangles) { tri.tri = t; tri.orient = 0; for (int i = 0; i < 3; i++) { tri.Sym(ref neighbor); int nid = neighbor.tri.id; if ((tri.tri.id < nid) || (nid == Mesh.DUMMY)) { p1 = tri.Org(); p2 = tri.Dest(); tri.Pivot(ref sub); if (sub.seg.hash == Mesh.DUMMY) { yield return(new Segment(p1, p2)); } else if (segments) { // Segments might be processed separately, so only // include them if requested. yield return(sub.seg); } } tri.orient++; } } }
public bool MoveNext() { if (tri.tri == null) { return(false); } current = null; while (current == null) { if (tri.orient == 3) { if (triangles.MoveNext()) { tri.tri = triangles.Current; tri.orient = 0; } else { // Finally no more triangles return(false); } } tri.Sym(ref neighbor); if ((tri.tri.id < neighbor.tri.id) || (neighbor.tri.id == Mesh.DUMMY)) { p1 = tri.Org(); p2 = tri.Dest(); tri.Pivot(ref sub); // Boundary mark of dummysub is 0, so we don't need to worry about that. current = new Edge(p1.id, p2.id, sub.seg.boundary); } tri.orient++; } return(true); }
public static void WriteOffFile(Mesh mesh, string filename) { Otri otri = new Otri(); Vertex value = null; long count = (long)mesh.vertices.Count; if (mesh.behavior.Jettison) { count = (long)(mesh.vertices.Count - mesh.undeads); } int num = 0; using (StreamWriter streamWriter = new StreamWriter(new FileStream(filename, FileMode.Create))) { streamWriter.WriteLine("OFF"); streamWriter.WriteLine("{0} {1} {2}", count, mesh.triangles.Count, mesh.edges); foreach (Vertex v in mesh.vertices.Values) { if (mesh.behavior.Jettison && v.type == VertexType.UndeadVertex) { continue; } double item = v[0]; string str = item.ToString(FileWriter.nfi); item = v[1]; streamWriter.WriteLine(" {0} {1} 0.0", str, item.ToString(FileWriter.nfi)); int num1 = num; num = num1 + 1; v.id = num1; } otri.orient = 0; foreach (Triangle triangle in mesh.triangles.Values) { otri.triangle = triangle; value = otri.Org(); Vertex vertex = otri.Dest(); Vertex vertex1 = otri.Apex(); streamWriter.WriteLine(" 3 {0} {1} {2}", value.id, vertex.id, vertex1.id); } } }
private void GetAspectHistogram(Mesh mesh) { int[] numArray = new int[16]; double[] numArray1 = new double[] { 1.5, 2, 2.5, 3, 4, 6, 10, 15, 25, 50, 100, 300, 1000, 10000, 100000, 0 }; Otri otri = new Otri(); Vertex[] vertexArray = new Vertex[3]; double[] numArray2 = new double[3]; double[] numArray3 = new double[3]; double[] numArray4 = new double[3]; otri.orient = 0; foreach (Triangle value in mesh.triangles.Values) { otri.triangle = value; vertexArray[0] = otri.Org(); vertexArray[1] = otri.Dest(); vertexArray[2] = otri.Apex(); double num = 0; for (int i = 0; i < 3; i++) { int num1 = Statistic.plus1Mod3[i]; int num2 = Statistic.minus1Mod3[i]; numArray2[i] = vertexArray[num1].x - vertexArray[num2].x; numArray3[i] = vertexArray[num1].y - vertexArray[num2].y; numArray4[i] = numArray2[i] * numArray2[i] + numArray3[i] * numArray3[i]; if (numArray4[i] > num) { num = numArray4[i]; } } double num3 = Math.Abs((vertexArray[2].x - vertexArray[0].x) * (vertexArray[1].y - vertexArray[0].y) - (vertexArray[1].x - vertexArray[0].x) * (vertexArray[2].y - vertexArray[0].y)) / 2; double num4 = num / (num3 * num3 / num); int num5 = 0; while (num4 > numArray1[num5] * numArray1[num5] && num5 < 15) { num5++; } numArray[num5] = numArray[num5] + 1; } }