delphicolorsfiremonkeydelphi-12-athens

How can I generate 10 visually distinct random colors in Delphi FMX?


I'm working on a Delphi FMX project where I need to generate a set of 10 random colors for use in a UI. The problem is that when I use TAlphaColorRec with random RGB values, many of the colors end up looking too similar.

For example, multiple shades of blue or green that are hard to tell apart.

This is my current code that generates the numbers:

function GenerateRandomColors(Count: UInt64): TArray<TAlphaColor>;
begin
  SetLength(Result, Count);
  for var i := 1 to Count do
  begin
    var C: TAlphaColorRec;
    C.R := Random(256);
    C.G := Random(256);
    C.B := Random(256);
    C.A := 255;
    Result[i-1] := C.Color;
  end;
end;

And I'm using it within this procedure:

procedure TForm1.GenerateColors;
begin
  Randomize;

  Memo1.Lines.Clear;
  GridLayout1.DeleteChildren;

  var Colors := GenerateRandomColors(10);
  for var Col in Colors do
  begin
    Memo1.Lines.Add(AlphaColorToString(Col));

    var Rect := TRectangle.Create(GridLayout1);
    Rect.Parent := GridLayout1;
    Rect.Fill.Color := Col;
    Rect.Stroke.Kind := TBrushKind.None;
  end;
end;

And this is how it looks:

Delphi Programming Colors

I need to modify GenerateRandomColors so that it generates colors that are more visually distinct from each other.


I have looked at the following questions already:

But the answers are not super useful because I need it to work with the Delphi Programming Language and most of those answers are using other programming languages.

Can someone please help me to modify GenerateRandomColors so that it generates distinct colors using Delphi within the FireMonkey (FMX) framework.


Solution

  • Thanks skamradt for pointing me in the right direction. This is the function I ended up making and using:

    uses
      System.UIConsts;
    
    function GenerateRandomDistinctColors(Count: UInt64): TArray<TAlphaColor>;
    begin
      SetLength(Result, Count);
      if Count = 0 then Exit;
    
      var reserved := 0;
      if Count > 0 then
      begin
        Result[reserved] := TAlphaColors.Black;
        Inc(reserved);
      end;
      if Count > 1 then
      begin
        Result[reserved] := TAlphaColors.White;
        Inc(reserved);
      end;
      if Count > 2 then
      begin
        Result[reserved] := TAlphaColors.Gray;
        Inc(reserved);
      end;
    
      var remain := Count - reserved;
      if remain <= 0 then Exit;
    
      var baseHue := Random * 360.0;
      var stepHue := 360.0 / remain;
    
      var j := 0;
      while j < remain do
      begin
        var hue := baseHue + j * stepHue + (Random * 2.0 - 1.0) * (stepHue * 0.08);
        hue := Frac(hue / 360.0) * 360.0;
    
        var sat := 0.6 + Random * 0.4; // 0.6..1.0
        var light := 0.45 + Random * 0.2; // 0.45..0.65
    
        Result[reserved + j] := HSLtoRGB(hue / 360.0, sat, light);
        Inc(j);
      end;
    end;
    

    It works similar to this answer, but modified to provide a slightly wider ranger of colors.

    Here's an example of the colors it generated:

    10 squares displaying different colors

    They are now much more distinct from each other. 😁