123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- // -----------------------------------------------------------------------
- // <copyright file="MeshValidator.cs">
- // Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
- // Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
- // </copyright>
- // -----------------------------------------------------------------------
- namespace UnityEngine.U2D.Animation.TriangleNet
- {
- using System;
- using Animation.TriangleNet.Topology;
- using Animation.TriangleNet.Geometry;
- internal static class MeshValidator
- {
- private static RobustPredicates predicates = RobustPredicates.Default;
- /// <summary>
- /// Test the mesh for topological consistency.
- /// </summary>
- internal static bool IsConsistent(Mesh mesh)
- {
- Otri tri = default(Otri);
- Otri oppotri = default(Otri), oppooppotri = default(Otri);
- Vertex org, dest, apex;
- Vertex oppoorg, oppodest;
- var logger = Log.Instance;
- // Temporarily turn on exact arithmetic if it's off.
- bool saveexact = Behavior.NoExact;
- Behavior.NoExact = false;
- int horrors = 0;
- // Run through the list of triangles, checking each one.
- foreach (var t in mesh.triangles)
- {
- tri.tri = t;
- // Check all three edges of the triangle.
- for (tri.orient = 0; tri.orient < 3; tri.orient++)
- {
- org = tri.Org();
- dest = tri.Dest();
- if (tri.orient == 0)
- {
- // Only test for inversion once.
- // Test if the triangle is flat or inverted.
- apex = tri.Apex();
- if (predicates.CounterClockwise(org, dest, apex) <= 0.0)
- {
- if (Log.Verbose)
- {
- logger.Warning(String.Format("Triangle is flat or inverted (ID {0}).", t.id),
- "MeshValidator.IsConsistent()");
- }
- horrors++;
- }
- }
- // Find the neighboring triangle on this edge.
- tri.Sym(ref oppotri);
- if (oppotri.tri.id != Mesh.DUMMY)
- {
- // Check that the triangle's neighbor knows it's a neighbor.
- oppotri.Sym(ref oppooppotri);
- if ((tri.tri != oppooppotri.tri) || (tri.orient != oppooppotri.orient))
- {
- if (tri.tri == oppooppotri.tri && Log.Verbose)
- {
- logger.Warning("Asymmetric triangle-triangle bond: (Right triangle, wrong orientation)",
- "MeshValidator.IsConsistent()");
- }
- horrors++;
- }
- // Check that both triangles agree on the identities
- // of their shared vertices.
- oppoorg = oppotri.Org();
- oppodest = oppotri.Dest();
- if ((org != oppodest) || (dest != oppoorg))
- {
- if (Log.Verbose)
- {
- logger.Warning("Mismatched edge coordinates between two triangles.",
- "MeshValidator.IsConsistent()");
- }
- horrors++;
- }
- }
- }
- }
- // Check for unconnected vertices
- mesh.MakeVertexMap();
- foreach (var v in mesh.vertices.Values)
- {
- if (v.tri.tri == null && Log.Verbose)
- {
- logger.Warning("Vertex (ID " + v.id + ") not connected to mesh (duplicate input vertex?)",
- "MeshValidator.IsConsistent()");
- }
- }
- // Restore the status of exact arithmetic.
- Behavior.NoExact = saveexact;
- return (horrors == 0);
- }
- /// <summary>
- /// Check if the mesh is (conforming) Delaunay.
- /// </summary>
- internal static bool IsDelaunay(Mesh mesh)
- {
- return IsDelaunay(mesh, false);
- }
- /// <summary>
- /// Check if that the mesh is (constrained) Delaunay.
- /// </summary>
- internal static bool IsConstrainedDelaunay(Mesh mesh)
- {
- return IsDelaunay(mesh, true);
- }
- /// <summary>
- /// Ensure that the mesh is (constrained) Delaunay.
- /// </summary>
- private static bool IsDelaunay(Mesh mesh, bool constrained)
- {
- Otri loop = default(Otri);
- Otri oppotri = default(Otri);
- Osub opposubseg = default(Osub);
- Vertex org, dest, apex;
- Vertex oppoapex;
- bool shouldbedelaunay;
- var logger = Log.Instance;
- // Temporarily turn on exact arithmetic if it's off.
- bool saveexact = Behavior.NoExact;
- Behavior.NoExact = false;
- int horrors = 0;
- var inf1 = mesh.infvertex1;
- var inf2 = mesh.infvertex2;
- var inf3 = mesh.infvertex3;
- // Run through the list of triangles, checking each one.
- foreach (var tri in mesh.triangles)
- {
- loop.tri = tri;
- // Check all three edges of the triangle.
- for (loop.orient = 0; loop.orient < 3; loop.orient++)
- {
- org = loop.Org();
- dest = loop.Dest();
- apex = loop.Apex();
- loop.Sym(ref oppotri);
- oppoapex = oppotri.Apex();
- // Only test that the edge is locally Delaunay if there is an
- // adjoining triangle whose pointer is larger (to ensure that
- // each pair isn't tested twice).
- shouldbedelaunay = (loop.tri.id < oppotri.tri.id) &&
- !Otri.IsDead(oppotri.tri) && (oppotri.tri.id != Mesh.DUMMY) &&
- (org != inf1) && (org != inf2) && (org != inf3) &&
- (dest != inf1) && (dest != inf2) && (dest != inf3) &&
- (apex != inf1) && (apex != inf2) && (apex != inf3) &&
- (oppoapex != inf1) && (oppoapex != inf2) && (oppoapex != inf3);
- if (constrained && mesh.checksegments && shouldbedelaunay)
- {
- // If a subsegment separates the triangles, then the edge is
- // constrained, so no local Delaunay test should be done.
- loop.Pivot(ref opposubseg);
- if (opposubseg.seg.hash != Mesh.DUMMY)
- {
- shouldbedelaunay = false;
- }
- }
- if (shouldbedelaunay)
- {
- if (predicates.NonRegular(org, dest, apex, oppoapex) > 0.0)
- {
- if (Log.Verbose)
- {
- logger.Warning(String.Format("Non-regular pair of triangles found (IDs {0}/{1}).",
- loop.tri.id, oppotri.tri.id), "MeshValidator.IsDelaunay()");
- }
- horrors++;
- }
- }
- }
- }
- // Restore the status of exact arithmetic.
- Behavior.NoExact = saveexact;
- return (horrors == 0);
- }
- }
- }
|