0

It's for a Mandelbrot set rendering (see: https://en.wikipedia.org/wiki/Mandelbrot_set); the color of each point should be based on the number of iterations it took for the complex number Z to escape the set.

I would like to map the colors such that if the point is an element of the Mandelbrot set, it should be purely red [RGB(255, 0, 0), 0% across spectrum from IR to UV].

If the calculation was stopped because the loop reached the iteration cap, the the color should be purely violet [RGB(249, 192, 255), 100% across spectrum].

I imagine the solution involves something like:

//where iterCount is the value for that point, maxIters is the iteration cap
double spectrumValue=iterCount/maxIters; //percent in decimal form
setColor(RGBConversion(spectrumValue));

However, the part I don't know how to do is the RGBConversion method. Ideally, it should run in constant time.

Mat Jones
  • 936
  • 1
  • 10
  • 27
  • Doesn't a simple `if` statement checking if `iterCount` is equal to `maxIters` give you the opportunity to specify two different colors? – Kenney Nov 20 '15 at 17:13
  • The iteration gradient is not uniform, it gets steeper close to the M-Set. So an even colour gradient will show very few pixels of the maximum colour, and you could consider that when building the `array[maxiters]`. My method was to create an `array[256]` of graduated colours which wraps smoothly when indexed as `array[iterations % 256]`. But also consider that iterations near the M-Set are pretty chaotic, your single colour gradient would probably look better than my method, where I forced neighbouring pixels having very different iterations, to be mid-grey (M-Set itself black). – Weather Vane Nov 20 '15 at 17:52
  • @Kenney yes, but that only gives me 2 colors, whereas I need a gradient between the two that includes hundreds or maybe thousands of colors. – Mat Jones Nov 20 '15 at 18:03
  • @WeatherVane could you please explain a bit clearer what you mean? I'm assuming you mean to store the colors in array[256], but A, I need more colors than that, and B, what is the index "iterations % 256" achieving? – Mat Jones Nov 20 '15 at 18:05
  • @mjones.udri I mean my colours wrap, so if the iterations are 256 the colour will be from `array[0]`, the colours repeat every 256 iterations. I faded blue -> green (no red) then green -> red (no blue), and then red -> blue (no green) within the 256 array, actually 255 I think (3 * 85). – Weather Vane Nov 20 '15 at 18:16
  • "thousands of colors" that will be unlikely if you are graduating one colour to another. The colour resolution of each component at the device is only 256, so the only way to have thousands of colours would look a mess. – Weather Vane Nov 20 '15 at 18:19

2 Answers2

3

You should be looking at using either "HSL" or "HSB" (aka "HSV") colour space, where the "H" in both stands for "hue". Hue is typically measured as an angle in degrees, with 0 degrees representing red, 120 for green, 240 for blue, although some libraries use the range 0..1

Keepping "S" and "B" constant and varying "H" linearly from the bottom of the range to the top will produce the typical "rainbow" of colours.

In your case since you're using Java and AWT, you should simply be able to call:

setColor(Color.getHSBColor(spectrumValue, 1.0, 1.0));
Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • Oh, good suggestion. This answer looks like it helps: http://stackoverflow.com/questions/2997656/how-can-i-use-the-hsl-colorspace-in-java – bcholmes Nov 20 '15 at 17:18
  • @bcholmes strictly speaking your answer does the same thing, but only works well for fully saturated colours. It's important in your method to include the tertiary colours (e.g. orange) otherwise the interpolation from red to green would miss those out. – Alnitak Nov 20 '15 at 17:22
  • I tried a solution similar to the one in the link posted by @bcholmes but I am just getting a solid red square; I know that the coloring is the problem, because I had the program generating an accurate rendering with other, arbitrary color map schemes. – Mat Jones Nov 20 '15 at 17:28
  • @Alnitak yes, I am using Java AWT Color. I am also using Java AWT Graphics, if that's relevant. – Mat Jones Nov 20 '15 at 17:38
  • OK, so just call `Color.getHSBColor(spectrumValue, 1.0, 1.0)` – Alnitak Nov 20 '15 at 17:39
  • @Alnitak I tried that, and it just made every single point completely red (RGB: 255, 0, 0) – Mat Jones Nov 20 '15 at 18:01
  • @mjones.udri so you need to confirm the range of your `spectrumValue` numbers - they need to be in the range 0..1 - see http://docs.oracle.com/javase/7/docs/api/java/awt/Color.html#getHSBColor(float,%20float,%20float) – Alnitak Nov 20 '15 at 18:05
  • spectrumValue<=1 for all circumstances, because iterCount<=maxIters; if iterCount reaches maxIters, I cut off the calculation. – Mat Jones Nov 20 '15 at 18:07
  • 1
    You may need to cast `iterCount` and `maxIters` to doubles or floats in your math to calculate `spectrumValue`. If they're integers, you'll always get an integer result. – bcholmes Nov 20 '15 at 19:12
1

You could start with an array of colours that represent key points in the spectrum: red, orange, yellow, green, blue, violet. Say they're equally spaced at 0, 0.2, 0.4, 0.6, 0.8 and 1. Then use this answer to smooth transition between them.

For each interval, you'd need to map the delta range -- 0.0 to 0.2 -- to a 0 to 1 ratio.

Community
  • 1
  • 1
bcholmes
  • 944
  • 1
  • 9
  • 23