226 lines
7.5 KiB
C#
226 lines
7.5 KiB
C#
using System;
|
|
using System.Text;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
|
|
namespace DrawGraph
|
|
{
|
|
/// <summary>
|
|
/// Hue-Saturation-Brightness Color class to store a color value, and to manage conversions
|
|
/// to and from RGB colors in the <see cref="Color" /> struct.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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
|
|
/// <see cref="byte" /> 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.
|
|
/// </remarks>
|
|
[Serializable]
|
|
public struct HSBColor
|
|
{
|
|
/// <summary>
|
|
/// The color hue value, ranging from 0 to 255.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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
|
|
/// </remarks>
|
|
public byte H;
|
|
/// <summary>
|
|
/// The color saturation (intensity) value, ranging from 0 (gray scale) to 255 (most colored).
|
|
/// </summary>
|
|
public byte S;
|
|
/// <summary>
|
|
/// The brightness value, ranging from 0 (black) to 255 (white).
|
|
/// </summary>
|
|
public byte B;
|
|
/// <summary>
|
|
/// The alpha value (opacity), ranging from 0 (transparent) to 255 (opaque).
|
|
/// </summary>
|
|
public byte A;
|
|
|
|
/// <summary>
|
|
/// Constructor to load an <see cref="HSBColor" /> struct from hue, saturation and
|
|
/// brightness values
|
|
/// </summary>
|
|
/// <param name="h">The color hue value, ranging from 0 to 255</param>
|
|
/// <param name="s">The color saturation (intensity) value, ranging from 0 (gray scale)
|
|
/// to 255 (most colored)</param>
|
|
/// <param name="b">The brightness value, ranging from 0 (black) to 255 (white)</param>
|
|
public HSBColor( int h, int s, int b )
|
|
{
|
|
this.H = (byte)h;
|
|
this.S = (byte)s;
|
|
this.B = (byte)b;
|
|
this.A = 255;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor to load an <see cref="HSBColor" /> struct from hue, saturation,
|
|
/// brightness, and alpha values
|
|
/// </summary>
|
|
/// <param name="h">The color hue value, ranging from 0 to 255</param>
|
|
/// <param name="s">The color saturation (intensity) value, ranging from 0 (gray scale)
|
|
/// to 255 (most colored)</param>
|
|
/// <param name="b">The brightness value, ranging from 0 (black) to 255 (white)</param>
|
|
/// <param name="a">The alpha value (opacity), ranging from 0 (transparent) to
|
|
/// 255 (opaque)</param>
|
|
public HSBColor( int a, int h, int s, int b )
|
|
: this( h, s, b )
|
|
{
|
|
this.A = (byte)a;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor to load an <see cref="HSBColor" /> struct from a system
|
|
/// <see cref="Color" /> struct.
|
|
/// </summary>
|
|
/// <param name="color">An rgb <see cref="Color" /> struct containing the equivalent
|
|
/// color you want to generate</param>
|
|
public HSBColor( Color color )
|
|
{
|
|
this = FromRGB( color );
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Implicit conversion operator to convert directly from an <see cref="HSBColor" /> to
|
|
/// a <see cref="Color" /> struct.
|
|
/// </summary>
|
|
/// <param name="hsbColor">The <see cref="HSBColor" /> struct to be converted</param>
|
|
/// <returns>An equivalent <see cref="Color" /> struct that can be used in the GDI+
|
|
/// graphics library</returns>
|
|
public static implicit operator Color( HSBColor hsbColor )
|
|
{
|
|
return ToRGB( hsbColor );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert an <see cref="HSBColor" /> value to an equivalent <see cref="Color" /> value.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
|
|
/// </remarks>
|
|
/// <param name="hsbColor">The <see cref="HSBColor" /> struct to be converted</param>
|
|
/// <returns>An equivalent <see cref="Color" /> struct, compatible with the GDI+ library</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert this <see cref="HSBColor" /> value to an equivalent <see cref="Color" /> value.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
|
|
/// </remarks>
|
|
/// <returns>An equivalent <see cref="Color" /> struct, compatible with the GDI+ library</returns>
|
|
public Color ToRGB()
|
|
{
|
|
return ToRGB( this );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert a <see cref="Color" /> value to an equivalent <see cref="HSBColor" /> value.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
|
|
/// </remarks>
|
|
/// <returns>An equivalent <see cref="HSBColor" /> struct</returns>
|
|
public HSBColor FromRGB()
|
|
{
|
|
return FromRGB( this );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert a <see cref="Color" /> value to an equivalent <see cref="HSBColor" /> value.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
|
|
/// </remarks>
|
|
/// <param name="rgbColor">The <see cref="Color" /> struct to be converted</param>
|
|
/// <returns>An equivalent <see cref="HSBColor" /> struct</returns>
|
|
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;
|
|
}
|
|
|
|
}
|
|
}
|