Introduction
I decided to write my own color selector for use in my own .NET applications, something intuitive and simple, that would cover the entire spectrum of colors available. Plenty of such color selectors exist, but I thought it would be a good learning experience to re-invent the wheel entirely on my own. I wound up settling on the Maxwell color triangle, and getting it all to work right required dusting off some old Trigonometry books (just kidding, it only required Googling...).
Basically, what I decided to do was divide an equilateral triangle into 3 quadrilaterals, as regions where the color byte values are R = 255
, G = 255
and B = 255
, respectively. (The center obviously being defined as R=B=G=255
).
Within those respective regions, the values of the other two distal color components depend on the relative distance of the selected point from the other 2 vertices, those values being reduced from 255 in direct proportion to the distances.
The trick is of course to get those relative distances, and that obviously required using the Pythagorean theorem, sines and cosines. Simple basic trigonometry. For example, it required getting the vertices of the triangle, where Sqwidth
is the width of its bounding rectangle and THeight
is the height from the triangle base:
//
// VertexR = New PointF(Sqwidth / 2, 0)
// VertexG = New PointF(0, THeight)
// VertexB = New PointF(Sqwidth, THeight)
//
And for example, I also needed the side length of the equilateral triangle, the midpoints of each side of the triangle, the triangle center, etc.
//
// TriangleSideLength = (THeight ^ 2 + (Sqwidth / 2) ^ 2) ^ 0.5
//
// Dim midx As Double = Math.Abs((TriangleSideLength / 2) * Math.Cos(Rad60))
// Dim midy As Double = Math.Abs((TriangleSideLength / 2) * Math.Sin(Rad60))
// MidRB = New PointF(Sqwidth / 2 + midx, midy)
// MidRG = New PointF(Sqwidth / 2 - midx, midy)
// MidGB = New PointF(Sqwidth / 2, THeight)
//
// TriangleCenter = New Point(Sqwidth / 2, Math.Abs((TriangleSideLength / 2) / Math.Cos(Rad30)))
//
With a few more calculations, you can get the relative distance of your selected point from each of the two vertices, to determine how much to reduce those values from 255
.
Once the RGB values are calculated based on the selected point, that is defined as the "selected" color (SelectedColor
), but that alone doesn't give you all possible color combinations, only all combinations where one of R
, G
or B
is maximized (255
). So, I provided a brightness track bar (BrightnessTB
) that proportionally reduces the RGB
values of the SelectedColor
of the triangle, for the final output color. These are the values that are displayed in the NumericUpDowns
(rUD
, gUD
and bUD
).
//
// rUD.Value = Int(Math.Max(0, Math.Min(255, SelectedColor.R * BrightnessTB.Value / 100)))
// gUD.Value = Int(Math.Max(0, Math.Min(255, SelectedColor.G * BrightnessTB.Value / 100)))
// bUD.Value = Int(Math.Max(0, Math.Min(255, SelectedColor.B * BrightnessTB.Value / 100)))
//
Finally, when calling a dialog to change settings, you want your current settings automatically inputted into the dialog when it opens. To allow this, I had to make a routine to calculate the point corresponding to a given color combination of RGB
. (the commented out function: Public Function GetTrianglePointForColor(c As Color) As PointF)
Simple and intuitive (3 colors as 3 points of a triangle), with the satisfaction of being homegrown