TriangleWriter.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. // -----------------------------------------------------------------------
  2. // <copyright file="TriangleWriter.cs" company="">
  3. // Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
  4. // Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
  5. // </copyright>
  6. // -----------------------------------------------------------------------
  7. namespace UnityEngine.U2D.Animation.TriangleNet
  8. .IO
  9. {
  10. using System.Collections.Generic;
  11. using System.Globalization;
  12. using System.IO;
  13. using Animation.TriangleNet.Geometry;
  14. using Animation.TriangleNet.Topology;
  15. /// <summary>
  16. /// Helper methods for writing Triangle file formats.
  17. /// </summary>
  18. internal class TriangleWriter
  19. {
  20. static NumberFormatInfo nfi = NumberFormatInfo.InvariantInfo;
  21. /// <summary>
  22. /// Number the vertices and write them to a .node file.
  23. /// </summary>
  24. /// <param name="mesh"></param>
  25. /// <param name="filename"></param>
  26. public void Write(Mesh mesh, string filename)
  27. {
  28. WritePoly(mesh, Path.ChangeExtension(filename, ".poly"));
  29. WriteElements(mesh, Path.ChangeExtension(filename, ".ele"));
  30. }
  31. /// <summary>
  32. /// Number the vertices and write them to a .node file.
  33. /// </summary>
  34. /// <param name="mesh"></param>
  35. /// <param name="filename"></param>
  36. public void WriteNodes(Mesh mesh, string filename)
  37. {
  38. using (var writer = new StreamWriter(filename))
  39. {
  40. WriteNodes(writer, mesh);
  41. }
  42. }
  43. /// <summary>
  44. /// Number the vertices and write them to a .node file.
  45. /// </summary>
  46. private void WriteNodes(StreamWriter writer, Mesh mesh)
  47. {
  48. int outvertices = mesh.vertices.Count;
  49. int nextras = mesh.nextras;
  50. Behavior behavior = mesh.behavior;
  51. if (behavior.Jettison)
  52. {
  53. outvertices = mesh.vertices.Count - mesh.undeads;
  54. }
  55. if (writer != null)
  56. {
  57. // Number of vertices, number of dimensions, number of vertex attributes,
  58. // and number of boundary markers (zero or one).
  59. writer.WriteLine("{0} {1} {2} {3}", outvertices, mesh.mesh_dim, nextras,
  60. behavior.UseBoundaryMarkers ? "1" : "0");
  61. if (mesh.numbering == NodeNumbering.None)
  62. {
  63. // If the mesh isn't numbered yet, use linear node numbering.
  64. mesh.Renumber();
  65. }
  66. if (mesh.numbering == NodeNumbering.Linear)
  67. {
  68. // If numbering is linear, just use the dictionary values.
  69. WriteNodes(writer, mesh.vertices.Values, behavior.UseBoundaryMarkers,
  70. nextras, behavior.Jettison);
  71. }
  72. else
  73. {
  74. // If numbering is not linear, a simple 'foreach' traversal of the dictionary
  75. // values doesn't reflect the actual numbering. Use an array instead.
  76. // TODO: Could use a custom sorting function on dictionary values instead.
  77. Vertex[] nodes = new Vertex[mesh.vertices.Count];
  78. foreach (var node in mesh.vertices.Values)
  79. {
  80. nodes[node.id] = node;
  81. }
  82. WriteNodes(writer, nodes, behavior.UseBoundaryMarkers,
  83. nextras, behavior.Jettison);
  84. }
  85. }
  86. }
  87. /// <summary>
  88. /// Write the vertices to a stream.
  89. /// </summary>
  90. /// <param name="nodes"></param>
  91. /// <param name="writer"></param>
  92. private void WriteNodes(StreamWriter writer, IEnumerable<Vertex> nodes, bool markers,
  93. int attribs, bool jettison)
  94. {
  95. int index = 0;
  96. foreach (var vertex in nodes)
  97. {
  98. if (!jettison || vertex.type != VertexType.UndeadVertex)
  99. {
  100. // Vertex number, x and y coordinates.
  101. writer.Write("{0} {1} {2}", index, vertex.x.ToString(nfi), vertex.y.ToString(nfi));
  102. #if USE_ATTRIBS
  103. // Write attributes.
  104. for (int j = 0; j < attribs; j++)
  105. {
  106. writer.Write(" {0}", vertex.attributes[j].ToString(nfi));
  107. }
  108. #endif
  109. if (markers)
  110. {
  111. // Write the boundary marker.
  112. writer.Write(" {0}", vertex.label);
  113. }
  114. writer.WriteLine();
  115. index++;
  116. }
  117. }
  118. }
  119. /// <summary>
  120. /// Write the triangles to an .ele file.
  121. /// </summary>
  122. /// <param name="mesh"></param>
  123. /// <param name="filename"></param>
  124. public void WriteElements(Mesh mesh, string filename)
  125. {
  126. Otri tri = default(Otri);
  127. Vertex p1, p2, p3;
  128. bool regions = mesh.behavior.useRegions;
  129. int j = 0;
  130. tri.orient = 0;
  131. using (var writer = new StreamWriter(filename))
  132. {
  133. // Number of triangles, vertices per triangle, attributes per triangle.
  134. writer.WriteLine("{0} 3 {1}", mesh.triangles.Count, regions ? 1 : 0);
  135. foreach (var item in mesh.triangles)
  136. {
  137. tri.tri = item;
  138. p1 = tri.Org();
  139. p2 = tri.Dest();
  140. p3 = tri.Apex();
  141. // Triangle number, indices for three vertices.
  142. writer.Write("{0} {1} {2} {3}", j, p1.id, p2.id, p3.id);
  143. if (regions)
  144. {
  145. writer.Write(" {0}", tri.tri.label);
  146. }
  147. writer.WriteLine();
  148. // Number elements
  149. item.id = j++;
  150. }
  151. }
  152. }
  153. /// <summary>
  154. /// Write the segments and holes to a .poly file.
  155. /// </summary>
  156. /// <param name="polygon">Data source.</param>
  157. /// <param name="filename">File name.</param>
  158. /// <param name="writeNodes">Write nodes into this file.</param>
  159. /// <remarks>If the nodes should not be written into this file,
  160. /// make sure a .node file was written before, so that the nodes
  161. /// are numbered right.</remarks>
  162. public void WritePoly(IPolygon polygon, string filename)
  163. {
  164. bool hasMarkers = polygon.HasSegmentMarkers;
  165. using (var writer = new StreamWriter(filename))
  166. {
  167. // TODO: write vertex attributes
  168. writer.WriteLine("{0} 2 0 {1}", polygon.Points.Count, polygon.HasPointMarkers ? "1" : "0");
  169. // Write nodes to this file.
  170. WriteNodes(writer, polygon.Points, polygon.HasPointMarkers, 0, false);
  171. // Number of segments, number of boundary markers (zero or one).
  172. writer.WriteLine("{0} {1}", polygon.Segments.Count, hasMarkers ? "1" : "0");
  173. Vertex p, q;
  174. int j = 0;
  175. foreach (var seg in polygon.Segments)
  176. {
  177. p = seg.GetVertex(0);
  178. q = seg.GetVertex(1);
  179. // Segment number, indices of its two endpoints, and possibly a marker.
  180. if (hasMarkers)
  181. {
  182. writer.WriteLine("{0} {1} {2} {3}", j, p.ID, q.ID, seg.Label);
  183. }
  184. else
  185. {
  186. writer.WriteLine("{0} {1} {2}", j, p.ID, q.ID);
  187. }
  188. j++;
  189. }
  190. // Holes
  191. j = 0;
  192. writer.WriteLine("{0}", polygon.Holes.Count);
  193. foreach (var hole in polygon.Holes)
  194. {
  195. writer.WriteLine("{0} {1} {2}", j++, hole.X.ToString(nfi), hole.Y.ToString(nfi));
  196. }
  197. // Regions
  198. if (polygon.Regions.Count > 0)
  199. {
  200. j = 0;
  201. writer.WriteLine("{0}", polygon.Regions.Count);
  202. foreach (var region in polygon.Regions)
  203. {
  204. writer.WriteLine("{0} {1} {2} {3}", j, region.point.X.ToString(nfi),
  205. region.point.Y.ToString(nfi), region.id);
  206. j++;
  207. }
  208. }
  209. }
  210. }
  211. /// <summary>
  212. /// Write the segments and holes to a .poly file.
  213. /// </summary>
  214. /// <param name="mesh"></param>
  215. /// <param name="filename"></param>
  216. public void WritePoly(Mesh mesh, string filename)
  217. {
  218. WritePoly(mesh, filename, true);
  219. }
  220. /// <summary>
  221. /// Write the segments and holes to a .poly file.
  222. /// </summary>
  223. /// <param name="mesh">Data source.</param>
  224. /// <param name="filename">File name.</param>
  225. /// <param name="writeNodes">Write nodes into this file.</param>
  226. /// <remarks>If the nodes should not be written into this file,
  227. /// make sure a .node file was written before, so that the nodes
  228. /// are numbered right.</remarks>
  229. public void WritePoly(Mesh mesh, string filename, bool writeNodes)
  230. {
  231. Osub subseg = default(Osub);
  232. Vertex pt1, pt2;
  233. bool useBoundaryMarkers = mesh.behavior.UseBoundaryMarkers;
  234. using (var writer = new StreamWriter(filename))
  235. {
  236. if (writeNodes)
  237. {
  238. // Write nodes to this file.
  239. WriteNodes(writer, mesh);
  240. }
  241. else
  242. {
  243. // The zero indicates that the vertices are in a separate .node file.
  244. // Followed by number of dimensions, number of vertex attributes,
  245. // and number of boundary markers (zero or one).
  246. writer.WriteLine("0 {0} {1} {2}", mesh.mesh_dim, mesh.nextras,
  247. useBoundaryMarkers ? "1" : "0");
  248. }
  249. // Number of segments, number of boundary markers (zero or one).
  250. writer.WriteLine("{0} {1}", mesh.subsegs.Count,
  251. useBoundaryMarkers ? "1" : "0");
  252. subseg.orient = 0;
  253. int j = 0;
  254. foreach (var item in mesh.subsegs.Values)
  255. {
  256. subseg.seg = item;
  257. pt1 = subseg.Org();
  258. pt2 = subseg.Dest();
  259. // Segment number, indices of its two endpoints, and possibly a marker.
  260. if (useBoundaryMarkers)
  261. {
  262. writer.WriteLine("{0} {1} {2} {3}", j, pt1.id, pt2.id, subseg.seg.boundary);
  263. }
  264. else
  265. {
  266. writer.WriteLine("{0} {1} {2}", j, pt1.id, pt2.id);
  267. }
  268. j++;
  269. }
  270. // Holes
  271. j = 0;
  272. writer.WriteLine("{0}", mesh.holes.Count);
  273. foreach (var hole in mesh.holes)
  274. {
  275. writer.WriteLine("{0} {1} {2}", j++, hole.X.ToString(nfi), hole.Y.ToString(nfi));
  276. }
  277. // Regions
  278. if (mesh.regions.Count > 0)
  279. {
  280. j = 0;
  281. writer.WriteLine("{0}", mesh.regions.Count);
  282. foreach (var region in mesh.regions)
  283. {
  284. writer.WriteLine("{0} {1} {2} {3}", j, region.point.X.ToString(nfi),
  285. region.point.Y.ToString(nfi), region.id);
  286. j++;
  287. }
  288. }
  289. }
  290. }
  291. /// <summary>
  292. /// Write the edges to an .edge file.
  293. /// </summary>
  294. /// <param name="mesh"></param>
  295. /// <param name="filename"></param>
  296. public void WriteEdges(Mesh mesh, string filename)
  297. {
  298. Otri tri = default(Otri), trisym = default(Otri);
  299. Osub checkmark = default(Osub);
  300. Vertex p1, p2;
  301. Behavior behavior = mesh.behavior;
  302. using (var writer = new StreamWriter(filename))
  303. {
  304. // Number of edges, number of boundary markers (zero or one).
  305. writer.WriteLine("{0} {1}", mesh.NumberOfEdges, behavior.UseBoundaryMarkers ? "1" : "0");
  306. long index = 0;
  307. // To loop over the set of edges, loop over all triangles, and look at
  308. // the three edges of each triangle. If there isn't another triangle
  309. // adjacent to the edge, operate on the edge. If there is another
  310. // adjacent triangle, operate on the edge only if the current triangle
  311. // has a smaller pointer than its neighbor. This way, each edge is
  312. // considered only once.
  313. foreach (var item in mesh.triangles)
  314. {
  315. tri.tri = item;
  316. for (tri.orient = 0; tri.orient < 3; tri.orient++)
  317. {
  318. tri.Sym(ref trisym);
  319. if ((tri.tri.id < trisym.tri.id) || (trisym.tri.id == Mesh.DUMMY))
  320. {
  321. p1 = tri.Org();
  322. p2 = tri.Dest();
  323. if (behavior.UseBoundaryMarkers)
  324. {
  325. // Edge number, indices of two endpoints, and a boundary marker.
  326. // If there's no subsegment, the boundary marker is zero.
  327. if (behavior.useSegments)
  328. {
  329. tri.Pivot(ref checkmark);
  330. if (checkmark.seg.hash == Mesh.DUMMY)
  331. {
  332. writer.WriteLine("{0} {1} {2} {3}", index, p1.id, p2.id, 0);
  333. }
  334. else
  335. {
  336. writer.WriteLine("{0} {1} {2} {3}", index, p1.id, p2.id,
  337. checkmark.seg.boundary);
  338. }
  339. }
  340. else
  341. {
  342. writer.WriteLine("{0} {1} {2} {3}", index, p1.id, p2.id,
  343. trisym.tri.id == Mesh.DUMMY ? "1" : "0");
  344. }
  345. }
  346. else
  347. {
  348. // Edge number, indices of two endpoints.
  349. writer.WriteLine("{0} {1} {2}", index, p1.id, p2.id);
  350. }
  351. index++;
  352. }
  353. }
  354. }
  355. }
  356. }
  357. /// <summary>
  358. /// Write the triangle neighbors to a .neigh file.
  359. /// </summary>
  360. /// <param name="mesh"></param>
  361. /// <param name="filename"></param>
  362. /// <remarks>WARNING: Be sure WriteElements has been called before,
  363. /// so the elements are numbered right!</remarks>
  364. public void WriteNeighbors(Mesh mesh, string filename)
  365. {
  366. Otri tri = default(Otri), trisym = default(Otri);
  367. int n1, n2, n3;
  368. int i = 0;
  369. using (StreamWriter writer = new StreamWriter(filename))
  370. {
  371. // Number of triangles, three neighbors per triangle.
  372. writer.WriteLine("{0} 3", mesh.triangles.Count);
  373. foreach (var item in mesh.triangles)
  374. {
  375. tri.tri = item;
  376. tri.orient = 1;
  377. tri.Sym(ref trisym);
  378. n1 = trisym.tri.id;
  379. tri.orient = 2;
  380. tri.Sym(ref trisym);
  381. n2 = trisym.tri.id;
  382. tri.orient = 0;
  383. tri.Sym(ref trisym);
  384. n3 = trisym.tri.id;
  385. // Triangle number, neighboring triangle numbers.
  386. writer.WriteLine("{0} {1} {2} {3}", i++, n1, n2, n3);
  387. }
  388. }
  389. }
  390. }
  391. }