4

Hard to describe what I'm trying to do. I basically want to create a discrete rainbow gradient so that for any line of i number of JButtons, the colour gradient across them will look rainbow.

I have done the following but it only really creates a red gradient followed by green gradient followed by blue gradient:

Color[] c = new Color[i];
    for(int n = 0; n < i; n++) {
        if(n < i/3) {
            c[n] = new Color(255, 255/(n+1), 255/(n+1));
        } else if(n < 2*i/3) {
            c[n] = new Color(255/(n-(i/3)), 255, 255/(n-(i/3)));
        } else {
            c[n] = new Color(255/(n+1), 255/(n+1), 255);
        }
    }

Any Idea how I would be able to get some type of rainbow effect?

Thanks

EDIT:

Used a Sine function which seems to work slightly better, but not sure how to define it so I get one "rainbow wave" in the region I want:

for(int n = 0; n < i; n++) {
        c[n] = new Color((int)(Math.sin(n) * 127 + 128), (int)(Math.sin(n + Math.PI/2) * 127 + 128), (int)(Math.sin(n + Math.PI) * 127 + 128));
    }
Fraser Price
  • 899
  • 6
  • 15
  • 36
  • I have done this, but don't have the algorithm with me. It is not easy, it is a pretty complex algorithm from what I remember. I sat around in paint's color editor looking at how the RGB's worked on the 2D scale for a while before I figured out a useful algorithm. An example of what I did can be seen here (my color array is at the bottom) http://tinypic.com/view.php?pic=whl0eu&s=8#.U0Wz4_ldW3Q – zgc7009 Apr 09 '14 at 20:56
  • @zgc7009 looks pretty complicated! – Fraser Price Apr 09 '14 at 20:57
  • Still needs some tweaking, but yea it is pretty complex. When I get back to my desktop I will see if I can't find the algorithm for you to at least give you somewhere to start. – zgc7009 Apr 09 '14 at 20:58
  • Also consider `Color.getHSBColor`, seen [here](http://stackoverflow.com/a/9875534/230513). – trashgod Apr 09 '14 at 21:51

2 Answers2

15

Your code has the right idea, but you need to run through your colors a little bit differently.

Let's say you're starting with green:

Color(  0, 255,   0)

Slowly start adding in some red to get to yellow:

Color( 51, 255,   0)
Color(102, 255,   0)
Color(153, 255,   0)
Color(204, 255,   0)
Color(255, 255,   0)

Then, take out the green to get to red:

Color(255, 204,   0)
Color(255, 153,   0)
Color(255, 102,   0)
Color(255,  51,   0)
Color(255,   0,   0)

Now, add blue to get to purple:

Color(255,   0,  51)
Color(255,   0, 102)
Color(255,   0, 153)
Color(255,   0, 204)
Color(255,   0, 255)

Then, remove red to get to blue:

Color(204,   0, 255)
Color(153,   0, 255)
Color(102,   0, 255)
Color( 51,   0, 255)
Color(  0,   0, 255)

Add the green back in to get to cyan:

Color(  0,  51, 255)
Color(  0, 102, 255)
Color(  0, 153, 255)
Color(  0, 204, 255)
Color(  0, 255, 255)

And finally remove the blue to get back to green:

Color(  0, 255, 204)
Color(  0, 255, 153)
Color(  0, 255, 102)
Color(  0, 255,  51)
Color(  0, 255,   0)

In this circle, of course, you can start anywhere and go in either direction.

In code, it could look as simple as this:

List<Color> colors = new ArrayList<Color>();
for (int r=0; r<100; r++) colors.add(new Color(r*255/100,       255,         0));
for (int g=100; g>0; g--) colors.add(new Color(      255, g*255/100,         0));
for (int b=0; b<100; b++) colors.add(new Color(      255,         0, b*255/100));
for (int r=100; r>0; r--) colors.add(new Color(r*255/100,         0,       255));
for (int g=0; g<100; g++) colors.add(new Color(        0, g*255/100,       255));
for (int b=100; b>0; b--) colors.add(new Color(        0,       255, b*255/100));
                          colors.add(new Color(        0,       255,         0));

Here, the 100's are the number of steps for each fade, which you can adjust.

If you need the colors in an array instead, do this at the end:

Color[] c = colors.toArray(new Color[colors.size()]);

One thing to note: The human eye is MUCH more sensitive to green than to red and blue. So you might want to add and remove green with smaller steps than you would with red and blue. Just play with the different step-sizes until you get something that looks even.

PS: For what I've used it for, linear fading as described above is perfectly sufficient and looks as expected. I personally don't think you need to complicate things by using sin and cos or other math.

Markus A.
  • 12,349
  • 8
  • 52
  • 116
12

You can use the HSV (hue, saturation, value) Instead of a RGB. In HSV, the color range is affected by only one variable (hue). if you run from 0 to 360 you cover the entire range of colors.

HSV scheme

Example of code:

final int ARRAY_SIZE = 100;
double jump = 360.0 / (ARRAY_SIZE*1.0);
int[] colors = new int[ARRAY_SIZE];
for (int i = 0; i < colors.length; i++) {
    colors[i] = Color.HSVToColor(new float[]{(float) (jump*i), 1.0f, 1.0f});
}

If you want to cover only part of the color table (Use the picture I attached below). An example of an array of turquoise color for a red color:

final int ARRAY_SIZE = 100;
final int MAX_COLOR = 360;
final int MIN_COLOR = 160;
double jump = (MAX_COLOR-MIN_COLOR) / (ARRAY_SIZE*1.0);
int[] colors = new int[ARRAY_SIZE];
for (int i = 0; i < colors.length; i++) {
    colors[i] = Color.HSVToColor(new float[]{(float) (MIN_COLOR + (jump*i)), 1.0f, 1.0f});
}

HSV color scheme

Guy4444
  • 1,411
  • 13
  • 15