HsvColor.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace SmartCoalApplication.Core
  8. {
  9. /// <summary>
  10. /// Adapted from:
  11. /// "A Primer on Building a Color Picker User Control with GDI+ in Visual Basic .NET or C#"
  12. /// http://www.msdnaa.net/Resources/display.aspx?ResID=2460
  13. /// </summary>
  14. public struct HsvColor
  15. {
  16. public int Hue; // 0-360
  17. public int Saturation; // 0-100
  18. public int Value; // 0-100
  19. public static bool operator ==(HsvColor lhs, HsvColor rhs)
  20. {
  21. if ((lhs.Hue == rhs.Hue) &&
  22. (lhs.Saturation == rhs.Saturation) &&
  23. (lhs.Value == rhs.Value))
  24. {
  25. return true;
  26. }
  27. else
  28. {
  29. return false;
  30. }
  31. }
  32. public static bool operator !=(HsvColor lhs, HsvColor rhs)
  33. {
  34. return !(lhs == rhs);
  35. }
  36. public override bool Equals(object obj)
  37. {
  38. return this == (HsvColor)obj;
  39. }
  40. public override int GetHashCode()
  41. {
  42. return (Hue + (Saturation << 8) + (Value << 16)).GetHashCode(); ;
  43. }
  44. public HsvColor(int hue, int saturation, int value)
  45. {
  46. if (hue < 0 || hue > 360)
  47. {
  48. throw new ArgumentOutOfRangeException("hue", "must be in the range [0, 360]");
  49. }
  50. if (saturation < 0 || saturation > 100)
  51. {
  52. throw new ArgumentOutOfRangeException("saturation", "must be in the range [0, 100]");
  53. }
  54. if (value < 0 || value > 100)
  55. {
  56. throw new ArgumentOutOfRangeException("value", "must be in the range [0, 100]");
  57. }
  58. Hue = hue;
  59. Saturation = saturation;
  60. Value = value;
  61. }
  62. public static HsvColor FromColor(Color color)
  63. {
  64. RgbColor rgb = new RgbColor(color.R, color.G, color.B);
  65. return rgb.ToHsv();
  66. }
  67. public Color ToColor()
  68. {
  69. RgbColor rgb = ToRgb();
  70. return Color.FromArgb(rgb.Red, rgb.Green, rgb.Blue);
  71. }
  72. public RgbColor ToRgb()
  73. {
  74. // HsvColor contains values scaled as in the color wheel:
  75. double h;
  76. double s;
  77. double v;
  78. double r = 0;
  79. double g = 0;
  80. double b = 0;
  81. // Scale Hue to be between 0 and 360. Saturation
  82. // and value scale to be between 0 and 1.
  83. h = (double)Hue % 360;
  84. s = (double)Saturation / 100;
  85. v = (double)Value / 100;
  86. if (s == 0)
  87. {
  88. // If s is 0, all colors are the same.
  89. // This is some flavor of gray.
  90. r = v;
  91. g = v;
  92. b = v;
  93. }
  94. else
  95. {
  96. double p;
  97. double q;
  98. double t;
  99. double fractionalSector;
  100. int sectorNumber;
  101. double sectorPos;
  102. // The color wheel consists of 6 sectors.
  103. // Figure out which sector you're in.
  104. sectorPos = h / 60;
  105. sectorNumber = (int)(Math.Floor(sectorPos));
  106. // get the fractional part of the sector.
  107. // That is, how many degrees into the sector
  108. // are you?
  109. fractionalSector = sectorPos - sectorNumber;
  110. // Calculate values for the three axes
  111. // of the color.
  112. p = v * (1 - s);
  113. q = v * (1 - (s * fractionalSector));
  114. t = v * (1 - (s * (1 - fractionalSector)));
  115. // Assign the fractional colors to r, g, and b
  116. // based on the sector the angle is in.
  117. switch (sectorNumber)
  118. {
  119. case 0:
  120. r = v;
  121. g = t;
  122. b = p;
  123. break;
  124. case 1:
  125. r = q;
  126. g = v;
  127. b = p;
  128. break;
  129. case 2:
  130. r = p;
  131. g = v;
  132. b = t;
  133. break;
  134. case 3:
  135. r = p;
  136. g = q;
  137. b = v;
  138. break;
  139. case 4:
  140. r = t;
  141. g = p;
  142. b = v;
  143. break;
  144. case 5:
  145. r = v;
  146. g = p;
  147. b = q;
  148. break;
  149. }
  150. }
  151. // return an RgbColor structure, with values scaled
  152. // to be between 0 and 255.
  153. return new RgbColor((int)(r * 255), (int)(g * 255), (int)(b * 255));
  154. }
  155. public override string ToString()
  156. {
  157. return String.Format("({0}, {1}, {2})", Hue, Saturation, Value);
  158. }
  159. }
  160. }