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;
}
}
}