using System; using System.Text; using System.Drawing; using System.Drawing.Drawing2D; namespace DrawGraph { /// /// Hue-Saturation-Brightness Color class to store a color value, and to manage conversions /// to and from RGB colors in the struct. /// /// /// This class is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky. /// This struct stores the hue, saturation, brightness, and alpha values internally as /// values from 0 to 255. The hue represents a fraction of the 360 degrees /// of color space available. The saturation is the color intensity, where 0 represents gray scale /// and 255 is the most colored. For the brightness, 0 represents black and 255 /// represents white. /// [Serializable] public struct HSBColor { /// /// The color hue value, ranging from 0 to 255. /// /// /// This property is actually a rescaling of the 360 degrees on the color wheel to 255 /// possible values. Therefore, every 42.5 units is a new sector, with the following /// convention: red=0, yellow=42.5, green=85, cyan=127.5, blue=170, magenta=212.5 /// public byte H; /// /// The color saturation (intensity) value, ranging from 0 (gray scale) to 255 (most colored). /// public byte S; /// /// The brightness value, ranging from 0 (black) to 255 (white). /// public byte B; /// /// The alpha value (opacity), ranging from 0 (transparent) to 255 (opaque). /// public byte A; /// /// Constructor to load an struct from hue, saturation and /// brightness values /// /// The color hue value, ranging from 0 to 255 /// The color saturation (intensity) value, ranging from 0 (gray scale) /// to 255 (most colored) /// The brightness value, ranging from 0 (black) to 255 (white) public HSBColor( int h, int s, int b ) { this.H = (byte)h; this.S = (byte)s; this.B = (byte)b; this.A = 255; } /// /// Constructor to load an struct from hue, saturation, /// brightness, and alpha values /// /// The color hue value, ranging from 0 to 255 /// The color saturation (intensity) value, ranging from 0 (gray scale) /// to 255 (most colored) /// The brightness value, ranging from 0 (black) to 255 (white) /// The alpha value (opacity), ranging from 0 (transparent) to /// 255 (opaque) public HSBColor( int a, int h, int s, int b ) : this( h, s, b ) { this.A = (byte)a; } /// /// Constructor to load an struct from a system /// struct. /// /// An rgb struct containing the equivalent /// color you want to generate public HSBColor( Color color ) { this = FromRGB( color ); } /// /// Implicit conversion operator to convert directly from an to /// a struct. /// /// The struct to be converted /// An equivalent struct that can be used in the GDI+ /// graphics library public static implicit operator Color( HSBColor hsbColor ) { return ToRGB( hsbColor ); } /// /// Convert an value to an equivalent value. /// /// /// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky. /// /// The struct to be converted /// An equivalent struct, compatible with the GDI+ library public static Color ToRGB( HSBColor hsbColor ) { Color rgbColor = Color.Black; // Determine which sector of the color wheel contains this hue // hsbColor.H ranges from 0 to 255, and there are 6 sectors, so 42.5 per sector int sector = (int) Math.Floor( (double) hsbColor.H / 42.5 ); // Calculate where the hue lies within the sector for interpolation purpose double fraction = (double) hsbColor.H / 42.5 - (double) sector; double sFrac = (double) hsbColor.S / 255.0; byte p = (byte) (( (double) hsbColor.B * ( 1.0 - sFrac ) ) + 0.5); byte q = (byte) (( (double) hsbColor.B * ( 1.0 - sFrac * fraction ) ) + 0.5); byte t = (byte) (( (double) hsbColor.B * ( 1.0 - sFrac * ( 1.0 - fraction ) ) ) + 0.5); switch( sector ) { case 0: // red - yellow rgbColor = Color.FromArgb( hsbColor.A, hsbColor.B, t, p ); break; case 1: // yellow - green rgbColor = Color.FromArgb( hsbColor.A, q, hsbColor.B, p ); break; case 2: // green - cyan rgbColor = Color.FromArgb( hsbColor.A, p, hsbColor.B, t ); break; case 3: // cyan - blue rgbColor = Color.FromArgb( hsbColor.A, p, q, hsbColor.B ); break; case 4: // blue - magenta rgbColor = Color.FromArgb( hsbColor.A, t, p, hsbColor.B ); break; case 5: default: // magenta - red rgbColor = Color.FromArgb( hsbColor.A, hsbColor.B, p, q ); break; } return rgbColor; } /// /// Convert this value to an equivalent value. /// /// /// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky. /// /// An equivalent struct, compatible with the GDI+ library public Color ToRGB() { return ToRGB( this ); } /// /// Convert a value to an equivalent value. /// /// /// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky. /// /// An equivalent struct public HSBColor FromRGB() { return FromRGB( this ); } /// /// Convert a value to an equivalent value. /// /// /// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky. /// /// The struct to be converted /// An equivalent struct public static HSBColor FromRGB( Color rgbColor ) { double r = (double) rgbColor.R / 255.0; double g = (double) rgbColor.G / 255.0; double b = (double) rgbColor.B / 255.0; double min = Math.Min( Math.Min( r, g ), b ); double max = Math.Max( Math.Max( r, g ), b ); HSBColor hsbColor = new HSBColor( rgbColor.A, 0, 0, 0 ); hsbColor.B = (byte) ( max * 255.0 + 0.5 ); double delta = max - min; if ( max != 0.0 ) { hsbColor.S = (byte) ( delta / max * 255.0 + 0.5 ); } else { hsbColor.S = 0; hsbColor.H = 0; return hsbColor; } double h; if ( r == max ) h = ( g - b ) / delta; // between yellow & magenta else if ( g == max ) h = 2 + ( b - r ) / delta; // between cyan & yellow else h = 4 + ( r - g ) / delta; // between magenta & cyan hsbColor.H = (byte) ( h * 42.5 ); if ( hsbColor.H < 0 ) hsbColor.H += 255; return hsbColor; } } }