Search code examples
c#arrayslistcolorsgradient

C# - Better ways to sort a list of colors


So before someone calls this post a duplicate, let me explain. I'm trying to find more optimized sorting algorithms to organize a list of colors based on a list of hex values. I'm currently sorting colors based on hue. This is fine, but when there are a bunch of colors, it seems to generate allot of noise.

enter image description here

I'm currently trying to find C# ways of sorting a giant list of random hex values. I have referenced this stackoverflow question and used some knowledgement from this site and created my code bellow.

RichTextBox1:

#ee82ee // Violet
#008000 // Green
#ffa500 // Orange
#0000ff // Blue
#ff0000 // Red
#ffff00 // Yellow
#4b0082 // Indigo
// Create a List from each color within the richtextbox
List<Color> tiledata = new List<Color> ();
foreach (string line in richTextBox1.Lines)
{
    // Get Each Line From Richtoxbox And Convert The Hex
    tiledata.Add(System.Drawing.ColorTranslator.FromHtml(line));
}

// Sort colors based on HUE
// https://stackoverflow.com/a/62203405/8667430
var hexColorsSorted = tiledata.OrderBy(color => color.GetHue()).ThenBy(o => o.R * 3 + o.G * 2 + o.B * 1);

// Expand Each Item Of The List
foreach (var color in hexColorsSorted)
{
    // Output the data
    Console.WriteLine(ColorConverterExtensions.ToHexString(color));
}

From above, this will obviously sort the colors in the correct rainbow order. However once you introduce more so similar colors, things start getting very messy from the image above. Currently the sorting algorithm is only sorting based on HUE, then by RGB. Is there another way or more I can do to this to clean things up a bit? My only request is to allow it to work with List<Tuple<Color>> such as an example as bellow.

.OrderBy(color => color.Item3.GetHue()).ThenBy(o => o.Item3.R * 3 + o.Item3.G * 2 + o.Item3.B * 1)

Bellow is a sorting algorithm this method seems to try and follow but ultimately fails. It would be nice if things looked similar to the following step sorting algorithms.

enter image description here or enter image description here


Solution

  • Upd: I made an adjustment to match the hue orientation more like the example.

    I have recreated the style form your example, you just need to sort the array using this comparer:

    class ColorRampComparer : IComparer<Color>
    {
        public int Compare(Color a, Color b)
        {
            var c1 = Step(a);
            var c2 = Step(b);
    
            return ((IComparable)c1).CompareTo(c2);
        }
    
        private Tuple<int, int, int> Step(Color color, int repetitions = 8)
        {
            int lum = (int)Math.Sqrt(.241 * color.R + .691 * color.G + .068 * color.B);
    
            float hue = 1 - Rotate(color.GetHue(), 90) / 360;
            float lightness = color.GetBrightness();
    
            int h2 = (int)(hue * repetitions);
            int v2 = (int)(lightness * repetitions);
    
            // To achieve second style uncomment this condition
            //if ((h2 % 2) == 0)
            //    v2 = repetitions - v2;
            //else
            //    lum = repetitions - lum;
    
            return Tuple.Create(h2, lum, v2);
        }
    
        private float Rotate(float angle, float degrees)
        {
            angle = (angle + degrees) % 360;
            if (angle < 0) angle += 360;
            return angle;
        }
    }
    

    Results are the next:

    First example

    And if you uncomment the fragment in Step function, then it will look like this: Second example

    To sort an array or enumerable use Sort method:

    colors.Sort(new ColorRampComparer());