Gradient.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. namespace Terminal.Gui;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. public class Gradient
  6. {
  7. public List<Color> Spectrum { get; private set; }
  8. private readonly bool _loop;
  9. private readonly List<Color> _stops;
  10. private readonly List<int> _steps;
  11. public enum Direction
  12. {
  13. Vertical,
  14. Horizontal,
  15. Radial,
  16. Diagonal
  17. }
  18. public Gradient (IEnumerable<Color> stops, IEnumerable<int> steps, bool loop = false)
  19. {
  20. _stops = stops.ToList ();
  21. if (_stops.Count < 1)
  22. throw new ArgumentException ("At least one color stop must be provided.");
  23. _steps = steps.ToList ();
  24. if (_steps.Any (step => step < 1))
  25. throw new ArgumentException ("Steps must be greater than 0.");
  26. _loop = loop;
  27. Spectrum = GenerateGradient (_steps);
  28. }
  29. public Color GetColorAtFraction (double fraction)
  30. {
  31. if (fraction < 0 || fraction > 1)
  32. throw new ArgumentOutOfRangeException (nameof (fraction), "Fraction must be between 0 and 1.");
  33. int index = (int)(fraction * (Spectrum.Count - 1));
  34. return Spectrum [index];
  35. }
  36. private List<Color> GenerateGradient (IEnumerable<int> steps)
  37. {
  38. List<Color> gradient = new List<Color> ();
  39. if (_stops.Count == 1)
  40. {
  41. for (int i = 0; i < steps.Sum (); i++)
  42. {
  43. gradient.Add (_stops [0]);
  44. }
  45. return gradient;
  46. }
  47. if (_loop)
  48. {
  49. _stops.Add (_stops [0]);
  50. }
  51. var colorPairs = _stops.Zip (_stops.Skip (1), (start, end) => new { start, end });
  52. var stepsList = _steps.ToList ();
  53. foreach (var (colorPair, thesteps) in colorPairs.Zip (stepsList, (pair, step) => (pair, step)))
  54. {
  55. gradient.AddRange (InterpolateColors (colorPair.start, colorPair.end, thesteps));
  56. }
  57. return gradient;
  58. }
  59. private IEnumerable<Color> InterpolateColors (Color start, Color end, int steps)
  60. {
  61. for (int step = 0; step <= steps; step++)
  62. {
  63. double fraction = (double)step / steps;
  64. int r = (int)(start.R + fraction * (end.R - start.R));
  65. int g = (int)(start.G + fraction * (end.G - start.G));
  66. int b = (int)(start.B + fraction * (end.B - start.B));
  67. yield return new Color (r, g, b);
  68. }
  69. }
  70. public Dictionary<Point, Color> BuildCoordinateColorMapping (int maxRow, int maxColumn, Direction direction)
  71. {
  72. var gradientMapping = new Dictionary<Point, Color> ();
  73. switch (direction)
  74. {
  75. case Direction.Vertical:
  76. for (int row = 0; row <= maxRow; row++)
  77. {
  78. double fraction = maxRow == 0 ? 1.0 : (double)row / maxRow;
  79. Color color = GetColorAtFraction (fraction);
  80. for (int col = 0; col <= maxColumn; col++)
  81. {
  82. gradientMapping [new Point (col, row)] = color;
  83. }
  84. }
  85. break;
  86. case Direction.Horizontal:
  87. for (int col = 0; col <= maxColumn; col++)
  88. {
  89. double fraction = maxColumn == 0 ? 1.0 : (double)col / maxColumn;
  90. Color color = GetColorAtFraction (fraction);
  91. for (int row = 0; row <= maxRow; row++)
  92. {
  93. gradientMapping [new Point (col, row)] = color;
  94. }
  95. }
  96. break;
  97. case Direction.Radial:
  98. for (int row = 0; row <= maxRow; row++)
  99. {
  100. for (int col = 0; col <= maxColumn; col++)
  101. {
  102. double distanceFromCenter = FindNormalizedDistanceFromCenter (maxRow, maxColumn, new Point (col, row));
  103. Color color = GetColorAtFraction (distanceFromCenter);
  104. gradientMapping [new Point (col, row)] = color;
  105. }
  106. }
  107. break;
  108. case Direction.Diagonal:
  109. for (int row = 0; row <= maxRow; row++)
  110. {
  111. for (int col = 0; col <= maxColumn; col++)
  112. {
  113. double fraction = ((double)row * 2 + col) / (maxRow * 2 + maxColumn);
  114. Color color = GetColorAtFraction (fraction);
  115. gradientMapping [new Point (col, row)] = color;
  116. }
  117. }
  118. break;
  119. }
  120. return gradientMapping;
  121. }
  122. private double FindNormalizedDistanceFromCenter (int maxRow, int maxColumn, Point coord)
  123. {
  124. double centerX = maxColumn / 2.0;
  125. double centerY = maxRow / 2.0;
  126. double dx = coord.X - centerX;
  127. double dy = coord.Y - centerY;
  128. double distance = Math.Sqrt (dx * dx + dy * dy);
  129. double maxDistance = Math.Sqrt (centerX * centerX + centerY * centerY);
  130. return distance / maxDistance;
  131. }
  132. }