123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460 |
- // -----------------------------------------------------------------------
- // <copyright file="TriangleWriter.cs" company="">
- // 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
- .IO
- {
- using System.Collections.Generic;
- using System.Globalization;
- using System.IO;
- using Animation.TriangleNet.Geometry;
- using Animation.TriangleNet.Topology;
- /// <summary>
- /// Helper methods for writing Triangle file formats.
- /// </summary>
- internal class TriangleWriter
- {
- static NumberFormatInfo nfi = NumberFormatInfo.InvariantInfo;
- /// <summary>
- /// Number the vertices and write them to a .node file.
- /// </summary>
- /// <param name="mesh"></param>
- /// <param name="filename"></param>
- public void Write(Mesh mesh, string filename)
- {
- WritePoly(mesh, Path.ChangeExtension(filename, ".poly"));
- WriteElements(mesh, Path.ChangeExtension(filename, ".ele"));
- }
- /// <summary>
- /// Number the vertices and write them to a .node file.
- /// </summary>
- /// <param name="mesh"></param>
- /// <param name="filename"></param>
- public void WriteNodes(Mesh mesh, string filename)
- {
- using (var writer = new StreamWriter(filename))
- {
- WriteNodes(writer, mesh);
- }
- }
- /// <summary>
- /// Number the vertices and write them to a .node file.
- /// </summary>
- private void WriteNodes(StreamWriter writer, Mesh mesh)
- {
- int outvertices = mesh.vertices.Count;
- int nextras = mesh.nextras;
- Behavior behavior = mesh.behavior;
- if (behavior.Jettison)
- {
- outvertices = mesh.vertices.Count - mesh.undeads;
- }
- if (writer != null)
- {
- // Number of vertices, number of dimensions, number of vertex attributes,
- // and number of boundary markers (zero or one).
- writer.WriteLine("{0} {1} {2} {3}", outvertices, mesh.mesh_dim, nextras,
- behavior.UseBoundaryMarkers ? "1" : "0");
- if (mesh.numbering == NodeNumbering.None)
- {
- // If the mesh isn't numbered yet, use linear node numbering.
- mesh.Renumber();
- }
- if (mesh.numbering == NodeNumbering.Linear)
- {
- // If numbering is linear, just use the dictionary values.
- WriteNodes(writer, mesh.vertices.Values, behavior.UseBoundaryMarkers,
- nextras, behavior.Jettison);
- }
- else
- {
- // If numbering is not linear, a simple 'foreach' traversal of the dictionary
- // values doesn't reflect the actual numbering. Use an array instead.
- // TODO: Could use a custom sorting function on dictionary values instead.
- Vertex[] nodes = new Vertex[mesh.vertices.Count];
- foreach (var node in mesh.vertices.Values)
- {
- nodes[node.id] = node;
- }
- WriteNodes(writer, nodes, behavior.UseBoundaryMarkers,
- nextras, behavior.Jettison);
- }
- }
- }
- /// <summary>
- /// Write the vertices to a stream.
- /// </summary>
- /// <param name="nodes"></param>
- /// <param name="writer"></param>
- private void WriteNodes(StreamWriter writer, IEnumerable<Vertex> nodes, bool markers,
- int attribs, bool jettison)
- {
- int index = 0;
- foreach (var vertex in nodes)
- {
- if (!jettison || vertex.type != VertexType.UndeadVertex)
- {
- // Vertex number, x and y coordinates.
- writer.Write("{0} {1} {2}", index, vertex.x.ToString(nfi), vertex.y.ToString(nfi));
- #if USE_ATTRIBS
- // Write attributes.
- for (int j = 0; j < attribs; j++)
- {
- writer.Write(" {0}", vertex.attributes[j].ToString(nfi));
- }
- #endif
- if (markers)
- {
- // Write the boundary marker.
- writer.Write(" {0}", vertex.label);
- }
- writer.WriteLine();
- index++;
- }
- }
- }
- /// <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 (var writer = new StreamWriter(filename))
- {
- // 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>
- /// Write the segments and holes to a .poly file.
- /// </summary>
- /// <param name="polygon">Data source.</param>
- /// <param name="filename">File name.</param>
- /// <param name="writeNodes">Write nodes into this file.</param>
- /// <remarks>If the nodes should not be written into this file,
- /// make sure a .node file was written before, so that the nodes
- /// are numbered right.</remarks>
- public void WritePoly(IPolygon polygon, string filename)
- {
- bool hasMarkers = polygon.HasSegmentMarkers;
- using (var writer = new StreamWriter(filename))
- {
- // TODO: write vertex attributes
- writer.WriteLine("{0} 2 0 {1}", polygon.Points.Count, polygon.HasPointMarkers ? "1" : "0");
- // Write nodes to this file.
- WriteNodes(writer, polygon.Points, polygon.HasPointMarkers, 0, false);
- // Number of segments, number of boundary markers (zero or one).
- writer.WriteLine("{0} {1}", polygon.Segments.Count, hasMarkers ? "1" : "0");
- Vertex p, q;
- int j = 0;
- foreach (var seg in polygon.Segments)
- {
- p = seg.GetVertex(0);
- q = seg.GetVertex(1);
- // Segment number, indices of its two endpoints, and possibly a marker.
- if (hasMarkers)
- {
- writer.WriteLine("{0} {1} {2} {3}", j, p.ID, q.ID, seg.Label);
- }
- else
- {
- writer.WriteLine("{0} {1} {2}", j, p.ID, q.ID);
- }
- j++;
- }
- // Holes
- j = 0;
- writer.WriteLine("{0}", polygon.Holes.Count);
- foreach (var hole in polygon.Holes)
- {
- writer.WriteLine("{0} {1} {2}", j++, hole.X.ToString(nfi), hole.Y.ToString(nfi));
- }
- // Regions
- if (polygon.Regions.Count > 0)
- {
- j = 0;
- writer.WriteLine("{0}", polygon.Regions.Count);
- foreach (var region in polygon.Regions)
- {
- writer.WriteLine("{0} {1} {2} {3}", j, region.point.X.ToString(nfi),
- region.point.Y.ToString(nfi), region.id);
- j++;
- }
- }
- }
- }
- /// <summary>
- /// Write the segments and holes to a .poly file.
- /// </summary>
- /// <param name="mesh"></param>
- /// <param name="filename"></param>
- public void WritePoly(Mesh mesh, string filename)
- {
- WritePoly(mesh, filename, true);
- }
- /// <summary>
- /// Write the segments and holes to a .poly file.
- /// </summary>
- /// <param name="mesh">Data source.</param>
- /// <param name="filename">File name.</param>
- /// <param name="writeNodes">Write nodes into this file.</param>
- /// <remarks>If the nodes should not be written into this file,
- /// make sure a .node file was written before, so that the nodes
- /// are numbered right.</remarks>
- public void WritePoly(Mesh mesh, string filename, bool writeNodes)
- {
- Osub subseg = default(Osub);
- Vertex pt1, pt2;
- bool useBoundaryMarkers = mesh.behavior.UseBoundaryMarkers;
- using (var writer = new StreamWriter(filename))
- {
- if (writeNodes)
- {
- // Write nodes to this file.
- WriteNodes(writer, mesh);
- }
- else
- {
- // The zero indicates that the vertices are in a separate .node file.
- // Followed by number of dimensions, number of vertex attributes,
- // and number of boundary markers (zero or one).
- writer.WriteLine("0 {0} {1} {2}", mesh.mesh_dim, mesh.nextras,
- useBoundaryMarkers ? "1" : "0");
- }
- // Number of segments, number of boundary markers (zero or one).
- writer.WriteLine("{0} {1}", mesh.subsegs.Count,
- useBoundaryMarkers ? "1" : "0");
- subseg.orient = 0;
- int j = 0;
- foreach (var item in mesh.subsegs.Values)
- {
- subseg.seg = item;
- pt1 = subseg.Org();
- pt2 = subseg.Dest();
- // Segment number, indices of its two endpoints, and possibly a marker.
- if (useBoundaryMarkers)
- {
- writer.WriteLine("{0} {1} {2} {3}", j, pt1.id, pt2.id, subseg.seg.boundary);
- }
- else
- {
- writer.WriteLine("{0} {1} {2}", j, pt1.id, pt2.id);
- }
- j++;
- }
- // Holes
- j = 0;
- writer.WriteLine("{0}", mesh.holes.Count);
- foreach (var hole in mesh.holes)
- {
- writer.WriteLine("{0} {1} {2}", j++, hole.X.ToString(nfi), hole.Y.ToString(nfi));
- }
- // Regions
- if (mesh.regions.Count > 0)
- {
- j = 0;
- writer.WriteLine("{0}", mesh.regions.Count);
- foreach (var region in mesh.regions)
- {
- writer.WriteLine("{0} {1} {2} {3}", j, region.point.X.ToString(nfi),
- region.point.Y.ToString(nfi), region.id);
- j++;
- }
- }
- }
- }
- /// <summary>
- /// Write the edges to an .edge file.
- /// </summary>
- /// <param name="mesh"></param>
- /// <param name="filename"></param>
- public void WriteEdges(Mesh mesh, string filename)
- {
- Otri tri = default(Otri), trisym = default(Otri);
- Osub checkmark = default(Osub);
- Vertex p1, p2;
- Behavior behavior = mesh.behavior;
- using (var writer = new StreamWriter(filename))
- {
- // Number of edges, number of boundary markers (zero or one).
- writer.WriteLine("{0} {1}", mesh.NumberOfEdges, behavior.UseBoundaryMarkers ? "1" : "0");
- long index = 0;
- // To loop over the set of edges, loop over all triangles, and look at
- // the three edges of each triangle. If there isn't another triangle
- // adjacent to the edge, operate on the edge. If there is another
- // adjacent triangle, operate on the edge only if the current triangle
- // has a smaller pointer than its neighbor. This way, each edge is
- // considered only once.
- foreach (var item in mesh.triangles)
- {
- tri.tri = item;
- for (tri.orient = 0; tri.orient < 3; tri.orient++)
- {
- tri.Sym(ref trisym);
- if ((tri.tri.id < trisym.tri.id) || (trisym.tri.id == Mesh.DUMMY))
- {
- p1 = tri.Org();
- p2 = tri.Dest();
- if (behavior.UseBoundaryMarkers)
- {
- // Edge number, indices of two endpoints, and a boundary marker.
- // If there's no subsegment, the boundary marker is zero.
- if (behavior.useSegments)
- {
- tri.Pivot(ref checkmark);
- if (checkmark.seg.hash == Mesh.DUMMY)
- {
- writer.WriteLine("{0} {1} {2} {3}", index, p1.id, p2.id, 0);
- }
- else
- {
- writer.WriteLine("{0} {1} {2} {3}", index, p1.id, p2.id,
- checkmark.seg.boundary);
- }
- }
- else
- {
- writer.WriteLine("{0} {1} {2} {3}", index, p1.id, p2.id,
- trisym.tri.id == Mesh.DUMMY ? "1" : "0");
- }
- }
- else
- {
- // Edge number, indices of two endpoints.
- writer.WriteLine("{0} {1} {2}", index, p1.id, p2.id);
- }
- index++;
- }
- }
- }
- }
- }
- /// <summary>
- /// Write the triangle neighbors to a .neigh file.
- /// </summary>
- /// <param name="mesh"></param>
- /// <param name="filename"></param>
- /// <remarks>WARNING: Be sure WriteElements has been called before,
- /// so the elements are numbered right!</remarks>
- public void WriteNeighbors(Mesh mesh, string filename)
- {
- Otri tri = default(Otri), trisym = default(Otri);
- int n1, n2, n3;
- int i = 0;
- using (StreamWriter writer = new StreamWriter(filename))
- {
- // Number of triangles, three neighbors per triangle.
- writer.WriteLine("{0} 3", mesh.triangles.Count);
- foreach (var item in mesh.triangles)
- {
- tri.tri = item;
- tri.orient = 1;
- tri.Sym(ref trisym);
- n1 = trisym.tri.id;
- tri.orient = 2;
- tri.Sym(ref trisym);
- n2 = trisym.tri.id;
- tri.orient = 0;
- tri.Sym(ref trisym);
- n3 = trisym.tri.id;
- // Triangle number, neighboring triangle numbers.
- writer.WriteLine("{0} {1} {2} {3}", i++, n1, n2, n3);
- }
- }
- }
- }
- }
|