// ----------------------------------------------------------------------- // // Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/ // // ----------------------------------------------------------------------- namespace UnityEngine.U2D.Animation.TriangleNet .IO { using System; using System.Globalization; using System.IO; using System.IO.Compression; using System.Text; using Animation.TriangleNet.Topology; using Animation.TriangleNet.Geometry; /// /// Writes a the current mesh into a text file. /// /// /// File format: /// /// num_nodes /// id_1 nx ny mark /// ... /// id_n nx ny mark /// /// num_segs /// id_1 p1 p2 mark /// ... /// id_n p1 p2 mark /// /// num_tris /// id_1 p1 p2 p3 n1 n2 n3 /// ... /// id_n p1 p2 p3 n1 n2 n3 /// class DebugWriter { static NumberFormatInfo nfi = CultureInfo.InvariantCulture.NumberFormat; int iteration; string session; StreamWriter stream; string tmpFile; int[] vertices; int triangles; #region Singleton pattern private static readonly DebugWriter instance = new DebugWriter(); // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit static DebugWriter() {} private DebugWriter() {} internal static DebugWriter Session { get { return instance; } } #endregion /// /// Start a new session with given name. /// /// Name of the session (and output files). public void Start(string session) { this.iteration = 0; this.session = session; if (this.stream != null) { throw new Exception("A session is active. Finish before starting a new."); } this.tmpFile = Path.GetTempFileName(); this.stream = new StreamWriter(tmpFile); } /// /// Write complete mesh to file. /// public void Write(Mesh mesh, bool skip = false) { this.WriteMesh(mesh, skip); this.triangles = mesh.Triangles.Count; } /// /// Finish this session. /// public void Finish() { this.Finish(session + ".mshx"); } private void Finish(string path) { if (stream != null) { stream.Flush(); stream.Dispose(); stream = null; string header = "#!N" + this.iteration + Environment.NewLine; using (var gzFile = new FileStream(path, FileMode.Create)) { using (var gzStream = new GZipStream(gzFile, CompressionMode.Compress, false)) { byte[] bytes = Encoding.UTF8.GetBytes(header); gzStream.Write(bytes, 0, bytes.Length); // TODO: read with stream bytes = File.ReadAllBytes(tmpFile); gzStream.Write(bytes, 0, bytes.Length); } } File.Delete(this.tmpFile); } } private void WriteGeometry(IPolygon geometry) { stream.WriteLine("#!G{0}", this.iteration++); } private void WriteMesh(Mesh mesh, bool skip) { // Mesh may have changed, but we choose to skip if (triangles == mesh.triangles.Count && skip) { return; } // Header line stream.WriteLine("#!M{0}", this.iteration++); Vertex p1, p2, p3; if (VerticesChanged(mesh)) { HashVertices(mesh); // Number of vertices. stream.WriteLine("{0}", mesh.vertices.Count); foreach (var v in mesh.vertices.Values) { // Vertex number, x and y coordinates and marker. stream.WriteLine("{0} {1} {2} {3}", v.id, v.x.ToString(nfi), v.y.ToString(nfi), v.label); } } else { stream.WriteLine("0"); } // Number of segments. stream.WriteLine("{0}", mesh.subsegs.Count); Osub subseg = default(Osub); subseg.orient = 0; foreach (var item in mesh.subsegs.Values) { if (item.hash <= 0) { continue; } subseg.seg = item; p1 = subseg.Org(); p2 = subseg.Dest(); // Segment number, indices of its two endpoints, and marker. stream.WriteLine("{0} {1} {2} {3}", subseg.seg.hash, p1.id, p2.id, subseg.seg.boundary); } Otri tri = default(Otri), trisym = default(Otri); tri.orient = 0; int n1, n2, n3, h1, h2, h3; // Number of triangles. stream.WriteLine("{0}", mesh.triangles.Count); foreach (var item in mesh.triangles) { tri.tri = item; p1 = tri.Org(); p2 = tri.Dest(); p3 = tri.Apex(); h1 = (p1 == null) ? -1 : p1.id; h2 = (p2 == null) ? -1 : p2.id; h3 = (p3 == null) ? -1 : p3.id; // Triangle number, indices for three vertices. stream.Write("{0} {1} {2} {3}", tri.tri.hash, h1, h2, h3); tri.orient = 1; tri.Sym(ref trisym); n1 = trisym.tri.hash; tri.orient = 2; tri.Sym(ref trisym); n2 = trisym.tri.hash; tri.orient = 0; tri.Sym(ref trisym); n3 = trisym.tri.hash; // Neighboring triangle numbers. stream.WriteLine(" {0} {1} {2}", n1, n2, n3); } } private bool VerticesChanged(Mesh mesh) { if (vertices == null || mesh.Vertices.Count != vertices.Length) { return true; } int i = 0; foreach (var v in mesh.Vertices) { if (v.id != vertices[i++]) { return true; } } return false; } private void HashVertices(Mesh mesh) { if (vertices == null || mesh.Vertices.Count != vertices.Length) { vertices = new int[mesh.Vertices.Count]; } int i = 0; foreach (var v in mesh.Vertices) { vertices[i++] = v.id; } } } }