/// <summary> /// Process all trianlges connected to given triangle and apply given action. /// </summary> /// <param name="triangle">The seeding triangle.</param> /// <param name="action">The action to apply to each triangle.</param> /// <param name="boundary">If non-zero, process all triangles of the /// region that is enclosed by segments with given boundary label.</param> public void Process(Triangle triangle, Action<Triangle> action, int boundary = 0) { // Make sure the triangle under consideration still exists. // It may have been eaten by the virus. if (triangle.id == Mesh.DUMMY || Otri.IsDead(triangle)) { return; } // Add the seeding triangle to the region. region.Add(triangle); triangle.infected = true; if (boundary == 0) { // Stop at any subsegment. ProcessRegion(action, seg => seg.hash == Mesh.DUMMY); } else { // Stop at segments that have the given boundary label. ProcessRegion(action, seg => seg.boundary != boundary); } // Free up memory (virus pool should be empty anyway). region.Clear(); }
/// <summary> /// Set the region attribute of all trianlges connected to given triangle. /// </summary> /// <param name="triangle">The triangle seed.</param> /// <param name="boundary">If non-zero, process all triangles of the /// region that is enclosed by segments with given boundary label.</param> public void Process(Triangle triangle, int boundary = 0) { this.Process(triangle, (tri) => { // Set the region id and area constraint. tri.label = triangle.label; tri.area = triangle.area; }, boundary); }
public QualityMesher(Mesh mesh, Configuration config) { logger = Log.Instance; badsubsegs = new Queue<BadSubseg>(); queue = new BadTriQueue(); this.mesh = mesh; this.predicates = config.Predicates(); this.behavior = mesh.behavior; newLocation = new NewLocation(mesh, predicates); newvertex_tri = new Triangle(); }
/** * Defines if points is inside triangle * Based on http://wiki.unity3d.com/index.php?title=PolyContainsPoint */ public static bool ContainsPoint(this TriangleNet.Topology.Triangle triangle, Vector3 p) { Vector3[] v = triangle.vertices.Select(vert => vert.ToVector3()).ToArray(); int j = v.Length - 1; // Last index bool inside = false; for (int i = 0; i < v.Length; j = i++) { if (((v[i].z <= p.z && p.z < v[j].z) || (v[j].z <= p.z && p.z < v[i].z)) && (p.x < (v[j].x - v[i].x) * (p.z - v[i].z) / (v[j].z - v[i].z) + v[i].x)) { inside = !inside; } } return(inside); }
/// <summary> /// Dissolve a bond (from one side). /// </summary> /// <remarks>Note that the other triangle will still think it's connected to /// this triangle. Usually, however, the other triangle is being deleted /// entirely, or bonded to another triangle, so it doesn't matter. /// </remarks> internal void Dissolve(Triangle dummy) { tri.neighbors[orient].tri = dummy; tri.neighbors[orient].orient = 0; }
/// <summary> /// Dissolve a bond (from the subsegment side). /// </summary> internal void TriDissolve(Triangle dummy) { seg.triangles[orient].tri = dummy; }
private void Initialize() { dummysub = new SubSegment(); dummysub.hash = DUMMY; // Initialize the two adjoining subsegments to be the omnipresent // subsegment. These will eventually be changed by various bonding // operations, but their values don't really matter, as long as they // can legally be dereferenced. dummysub.subsegs[0].seg = dummysub; dummysub.subsegs[1].seg = dummysub; // Set up 'dummytri', the 'triangle' that occupies "outer space." dummytri = new Triangle(); dummytri.hash = dummytri.id = DUMMY; // Initialize the three adjoining triangles to be "outer space." These // will eventually be changed by various bonding operations, but their // values don't really matter, as long as they can legally be // dereferenced. dummytri.neighbors[0].tri = dummytri; dummytri.neighbors[1].tri = dummytri; dummytri.neighbors[2].tri = dummytri; // Initialize the three adjoining subsegments of 'dummytri' to be // the omnipresent subsegment. dummytri.subsegs[0].seg = dummysub; dummytri.subsegs[1].seg = dummysub; dummytri.subsegs[2].seg = dummysub; }
/// <summary> /// Deallocate space for a triangle, marking it dead. /// </summary> /// <param name="dyingtriangle"></param> internal void TriangleDealloc(Triangle dyingtriangle) { // Mark the triangle as dead. This makes it possible to detect dead // triangles when traversing the list of all triangles. Otri.Kill(dyingtriangle); triangles.Release(dyingtriangle); }
public GraphNode(TriangleNet.Topology.Triangle triangle) { this.triangle = triangle; this.center = new PointStruct(triangle.GetCentroid()); }
/// <summary> /// Find the abutting triangle; same edge. [sym(abc) -> ba*] /// </summary> public void Sym() { int tmp = orient; orient = tri.neighbors[tmp].orient; tri = tri.neighbors[tmp].tri; }
/// <summary> /// Set a triangle's deallocation. /// </summary> internal static void Kill(Triangle tri) { tri.neighbors[0].tri = null; tri.neighbors[2].tri = null; }
/// <summary> /// Check a triangle's deallocation. /// </summary> internal static bool IsDead(Triangle tria) { return tria.neighbors[0].tri == null; }
/// <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> private void CarveHoles() { Otri searchtri = default(Otri); Vertex searchorg, searchdest; LocateResult intersect; Triangle[] regionTris = null; 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 (predicates.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); } } } } } // Now, we have to find all the regions BEFORE we carve the holes, because locate() won't // work when the triangulation is no longer convex. (Incidentally, this is the reason why // regional attributes and area constraints can't be used when refining a preexisting mesh, // which might not be convex; they can only be used with a freshly triangulated PSLG.) if (mesh.regions.Count > 0) { int i = 0; regionTris = new Triangle[mesh.regions.Count]; // Find the starting triangle for each region. foreach (var region in mesh.regions) { regionTris[i] = dummytri; // Ignore region points that aren't within the bounds of the mesh. if (mesh.bounds.Contains(region.point)) { // Start searching from some triangle on the outer boundary. searchtri.tri = dummytri; searchtri.orient = 0; searchtri.Sym(); // Ensure that the region point is to the left of this boundary // edge; otherwise, locate() will falsely report that the // region point falls within the starting triangle. searchorg = searchtri.Org(); searchdest = searchtri.Dest(); if (predicates.CounterClockwise(searchorg, searchdest, region.point) > 0.0) { // Find a triangle that contains the region point. intersect = mesh.locator.Locate(region.point, ref searchtri); if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected())) { // Record the triangle for processing after the // holes have been carved. regionTris[i] = searchtri.tri; regionTris[i].label = region.id; regionTris[i].area = region.area; } } } i++; } } if (viri.Count > 0) { // Carve the holes and concavities. Plague(); } if (regionTris != null) { var iterator = new RegionIterator(mesh); for (int i = 0; i < regionTris.Length; i++) { if (regionTris[i].id != Mesh.DUMMY) { // Make sure the triangle under consideration still exists. // It may have been eaten by the virus. if (!Otri.IsDead(regionTris[i])) { // Apply one region's attribute and/or area constraint. iterator.Process(regionTris[i]); } } } } // Free up memory (virus pool should be empty anyway). viri.Clear(); }
/// <summary> /// Find the previous edge (clockwise) of the adjacent triangle. [rprev(abc) -> b**] /// </summary> public void Rprev() { //SymSelf(); int tmp = orient; orient = tri.neighbors[tmp].orient; tri = tri.neighbors[tmp].tri; //LprevSelf(); orient = minus1Mod3[orient]; //SymSelf(); tmp = orient; orient = tri.neighbors[tmp].orient; tri = tri.neighbors[tmp].tri; }
/// <summary> /// Find the next edge (counterclockwise) of the adjacent triangle. [rnext(abc) -> *a*] /// </summary> public void Rnext() { //SymSelf(); int tmp = orient; orient = tri.neighbors[tmp].orient; tri = tri.neighbors[tmp].tri; //LnextSelf(); orient = plus1Mod3[orient]; //SymSelf(); tmp = orient; orient = tri.neighbors[tmp].orient; tri = tri.neighbors[tmp].tri; }
/// <summary> /// Create a new triangle with orientation zero. /// </summary> /// <param name="newotri">Reference to the new triangle.</param> internal void MakeTriangle(ref Otri newotri) { Triangle tri = new Triangle(); tri.hash = tri.id = this.hash_tri++; tri.subsegs[0].seg = dummysub; tri.subsegs[1].seg = dummysub; tri.subsegs[2].seg = dummysub; tri.neighbors[0].tri = dummytri; tri.neighbors[1].tri = dummytri; tri.neighbors[2].tri = dummytri; newotri.tri = tri; newotri.orient = 0; triangles.Add(tri.hash, tri); }
/// <summary> /// Set the region attribute of all trianlges connected to given triangle. /// </summary> public void Process(Triangle triangle) { // Default action is to just set the region id for all trianlges. this.Process(triangle, (tri) => { tri.label = triangle.label; }); }
/// <summary> /// Process all trianlges connected to given triangle and apply given action. /// </summary> public void Process(Triangle triangle, Action<Triangle> func) { if (triangle.id != Mesh.DUMMY) { // Make sure the triangle under consideration still exists. // It may have been eaten by the virus. if (!Otri.IsDead(triangle)) { // Put one triangle in the virus pool. triangle.infected = true; viri.Add(triangle); // Apply one region's attribute and/or area constraint. ProcessRegion(func); // The virus pool should be empty now. } } // Free up memory (virus pool should be empty anyway). viri.Clear(); }