SimpleSmoother.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // -----------------------------------------------------------------------
  2. // <copyright file="SimpleSmoother.cs" company="">
  3. // Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
  4. // </copyright>
  5. // -----------------------------------------------------------------------
  6. namespace UnityEngine.U2D.Animation.TriangleNet
  7. .Smoothing
  8. {
  9. using System.Linq;
  10. using Animation.TriangleNet.Geometry;
  11. using Animation.TriangleNet.Meshing;
  12. using Animation.TriangleNet.Topology.DCEL;
  13. using Animation.TriangleNet.Voronoi;
  14. /// <summary>
  15. /// Simple mesh smoother implementation.
  16. /// </summary>
  17. /// <remarks>
  18. /// Vertices wich should not move (e.g. segment vertices) MUST have a
  19. /// boundary mark greater than 0.
  20. /// </remarks>
  21. internal class SimpleSmoother : ISmoother
  22. {
  23. TrianglePool pool;
  24. Configuration config;
  25. IVoronoiFactory factory;
  26. ConstraintOptions options;
  27. /// <summary>
  28. /// Initializes a new instance of the <see cref="SimpleSmoother" /> class.
  29. /// </summary>
  30. public SimpleSmoother()
  31. : this(new VoronoiFactory())
  32. {
  33. }
  34. /// <summary>
  35. /// Initializes a new instance of the <see cref="SimpleSmoother" /> class.
  36. /// </summary>
  37. public SimpleSmoother(IVoronoiFactory factory)
  38. {
  39. this.factory = factory;
  40. this.pool = new TrianglePool();
  41. this.config = new Configuration(
  42. () => RobustPredicates.Default,
  43. () => pool.Restart());
  44. this.options = new ConstraintOptions() { ConformingDelaunay = true };
  45. }
  46. /// <summary>
  47. /// Initializes a new instance of the <see cref="SimpleSmoother" /> class.
  48. /// </summary>
  49. /// <param name="factory">Voronoi object factory.</param>
  50. /// <param name="config">Configuration.</param>
  51. public SimpleSmoother(IVoronoiFactory factory, Configuration config)
  52. {
  53. this.factory = factory;
  54. this.config = config;
  55. this.options = new ConstraintOptions() { ConformingDelaunay = true };
  56. }
  57. public void Smooth(IMesh mesh)
  58. {
  59. Smooth(mesh, 10);
  60. }
  61. public void Smooth(IMesh mesh, int limit)
  62. {
  63. var smoothedMesh = (Mesh)mesh;
  64. var mesher = new GenericMesher(config);
  65. var predicates = config.Predicates();
  66. // The smoother should respect the mesh segment splitting behavior.
  67. this.options.SegmentSplitting = smoothedMesh.behavior.NoBisect;
  68. // Take a few smoothing rounds (Lloyd's algorithm).
  69. for (int i = 0; i < limit; i++)
  70. {
  71. Step(smoothedMesh, factory, predicates);
  72. // Actually, we only want to rebuild, if the mesh is no longer
  73. // Delaunay. Flipping edges could be the right choice instead
  74. // of re-triangulating...
  75. smoothedMesh = (Mesh)mesher.Triangulate(Rebuild(smoothedMesh), options);
  76. factory.Reset();
  77. }
  78. smoothedMesh.CopyTo((Mesh)mesh);
  79. }
  80. private void Step(Mesh mesh, IVoronoiFactory factory, IPredicates predicates)
  81. {
  82. var voronoi = new BoundedVoronoi(mesh, factory, predicates);
  83. if (!voronoi.IsConsistent())
  84. return;
  85. double x, y;
  86. foreach (var face in voronoi.Faces)
  87. {
  88. if (face.generator.label == 0)
  89. {
  90. Centroid(face, out x, out y);
  91. face.generator.x = x;
  92. face.generator.y = y;
  93. }
  94. }
  95. }
  96. /// <summary>
  97. /// Calculate the centroid of a polygon.
  98. /// </summary>
  99. private void Centroid(Face face, out double x, out double y)
  100. {
  101. double ai, atmp = 0, xtmp = 0, ytmp = 0;
  102. var edge = face.Edge;
  103. var first = edge.Next.ID;
  104. Point p, q;
  105. do
  106. {
  107. p = edge.Origin;
  108. q = edge.Twin.Origin;
  109. ai = p.x * q.y - q.x * p.y;
  110. atmp += ai;
  111. xtmp += (q.x + p.x) * ai;
  112. ytmp += (q.y + p.y) * ai;
  113. edge = edge.Next;
  114. }
  115. while (edge.Next.ID != first);
  116. x = xtmp / (3 * atmp);
  117. y = ytmp / (3 * atmp);
  118. //area = atmp / 2;
  119. }
  120. /// <summary>
  121. /// Rebuild the input geometry.
  122. /// </summary>
  123. private Polygon Rebuild(Mesh mesh)
  124. {
  125. var data = new Polygon(mesh.vertices.Count);
  126. foreach (var v in mesh.vertices.Values)
  127. {
  128. // Reset to input vertex.
  129. v.type = VertexType.InputVertex;
  130. data.Points.Add(v);
  131. }
  132. data.Segments.AddRange(mesh.subsegs.Values.Cast<ISegment>());
  133. data.Holes.AddRange(mesh.holes);
  134. data.Regions.AddRange(mesh.regions);
  135. return data;
  136. }
  137. }
  138. }