arrays,lists & map. mapping values to RGV values

"The code below stores a range of RGB values as arrays which is then stored in a list.
I want to then assign each specific array a temp value by using the std::map.
This is just one of the ways I've tried.
What I want to do is to just have an array of RGB values and assign temp values to each array"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main() 
{
	map<float, list<int>>heatMapData;

	list<array<int, 3>> blueToCyan{ {0,14,255}, {0,26,255}, {0,38,255}, {0,50,255}, {0,62,255}, {0,74,255}, {0,86,255},
								   {0,98,255}, {0,110,255},{0,122,255},{0,134,255},{0,146,255},{0,158,255},{0,170,255},
								   {0,182,255},{0,206,255},{0,218,255},{0,230,255},{0,242,255},{0,254,255},{0,194,255}
	};



	heatMapData.insert(pair<float, list<int>>(20.0,blueToCyan[0][0]));

Last edited on
std::list is implemented as linked list so accessing an element at a specific position is slow, you would have to step through each element one after another until you get to the right position, that's why it doesn't have a [] operator. Consider using std::vector instead.
Last edited on
Let me just pull out my crystal ball to answer the question you didn't ask.

std::lists aren't random access, so you don't have the [] operator.
You need to use iterators (begin/end), or if you just need to access the first element, you can do blueToCyan.front(),

Edit: But your other problem that I just noticed is that you're trying to insert a pair of (double, int) into a pair for (float, list<int>).

Even if you did blueToCyan.front() instead of blueToCyan.front()[0], blueToCyan.front() is a std::array, not a std::list. So maybe just make your object on line 5 be a list of lists?

Or just make a flattened 1D array. You're doing this fancy stuff with maps and lists and arrays, but 95% of the time, the answer is "use a vector".

Also, having a float value as the key for a map is very error-prone because there can be imperceptible small differences between two adjacent float values.

tl;dr your design appears flawed, what are you actually trying to accomplish?
Last edited on
yeah sorry bout no explanation, first time posting here, the quotation was missing.
What I am trying to do is to map temperature values to RGB values.
so essentially what I am attempting to do with my code is create an array containing the RGB values which is stored as a list , then associate the 20.0 to array blueToCyan[0][0].
I've tried other ways to get this done but this just something that I was thinking to try cause I just learned about maps, lists
Last edited on
Apologies if I came off as callous. So is 20.0 is a temperature? What if the temperature is 19.9 or 20.1? I assume that you'd want a slightly different input temperature to have a slightly different output RGB, right?

If you're trying to map temperatures to colors, I suggest having anchor RGB values for particular temperatures, and then interpolating between those RGB values for in-between temperatures. I've done almost the same thing in the past when mapping colors for fractal images.

But in your case, I don't think we need to be that generalized. You seem to be keeping R and B constant, but changing G. So you really only need a function that maps input temperature to output Green value. I think you meant to put your {0,194,255} in a different spot so it's increasing, right?
Your function for G appears to be
G = input * 12 + 2

So all you really need is something like:
1
2
3
4
5
6
#include <cmath>

int temperature_to_color(double temp)
{
    return static_cast<int>(std::round(temp * 12 + 2));
}


You can also handle values < 0, or > 255 in whatever way you want.

PS: Just for next time -- this has nothing to do with programming on Windows specifically; this is more of general C++ programming topic.
Last edited on
I could have sworn I selected general programming but was having issues posting the question, not sure how that happened

the {0,194,255} should be further up, but the range of colors should go from blue to cyan hence only the green values changing & an incremental increase of 12

the temperature values will vary between 20 & 24.75 degrees by increments of 0.25, so thats 20 different values, hence the 20 different RGB values.

My idea was to manually store all the RGB values in an array, then create an association between the each RGB and temperature values. eg 20 degrees would be {0,14,255} 20.25 would be {0,26,255} so on so so fourth.

I think its because I am using 2 dimensional array thats causing the issue. I'm thinking about converting the RGB to hex and then using a 1by 20 array instead and then use the map to key value pair to associate the 2 data.

I'm a try that and see how it goes but if you got any suggestions that'd be helpful
Last edited on
One minor inconsistency: Your original post has 21 values, but if we go by your latest post, there are only 20 values in range [20, 24.75] by 0.25 increments. So are there 21 output values, or 20?

I'm going to assume you want 20.0 degrees --> {0, 14, 255}, and 24.75 degrees --> {0, 254, 255}. If you don't want that, I think I made the code below flexible enough such that you can change it.

My idea was to manually store all the RGB values in an array, then create an association between the each RGB and temperature values. eg 20 degrees would be {0,14,255} 20.25 would be {0,26,255} so on so so fourth.
This isn't a bad idea, but I think it's fundamentally fragile unless you 100% know the exact values of the input values. I do not suggest having a float as the key to a map, because floating-point numbers are inherently inexact; e.g. if that 20.25 value comes as the result of a previous calculation or real measurement, it might actually be 20.249999, and then your map won't work.

Your temperature to RGB mapping is completely linear, so it can be accommodated without having to use a map structure.

Here's what I propose based on the details you just wrote. The output just shows some example inputs and outputs. This could be adapted with a bit more work to use a vector or a map if the color gradient ends up not being linear in RGB (e.g. a rainbow).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// Example program
#include <iostream>
#include <iomanip>
#include <string>
#include <cmath>

struct Color {
    int r;
    int g;
    int b;
};

// output color for demonstration
std::ostream& operator<<(std::ostream& os, const Color& color)
{
    return os << "(" << color.r << ", " << color.g << ", " << color.b << ")";   
}

double interpolate(double input,
    const double low_input, const double high_input,
    const double low_output, const double high_output)
{
    // clamp input values to the expected extremes
    // (comment this out if it doesn't suit your needs)
    if (input < low_input) input = low_input;
    if (input > high_input) input = high_input;

    // t - normalized parameter, [0.0, 1.0]
    // t == 0 --> output == low
    // t == 1 --> output == high
    double t = (input - low_input) / (high_input - low_input);
    
    return (1.0 - t) * low_output + t * high_output;
}

// 20.00 degrees --> {0, 14, 255}
// 20.25 degrees --> {0, 27, 255}
// ...
// 24.75 degrees --> {0, 254, 255}
Color temperature_to_color(double temperature)
{
    const double MinTemp = 20.0;
    const double MaxTemp = 24.75;
    const int MinGreen = 14;
    const int MaxGreen = 254;

    int green = static_cast<int>(std::round(
        interpolate(temperature, MinTemp, MaxTemp, MinGreen, MaxGreen)));
    
    return Color { 0, green, 255 };
}

int main()
{
    std::cout.precision(2);
    for (double temp = 20.0; temp <= 24.75 + 0.01; temp += 0.25)
    {
        std::cout << std::fixed << temp << " degrees --> " << temperature_to_color(temp) << '\n';
    }
}

20.00 degrees --> (0, 14, 255)
20.25 degrees --> (0, 27, 255)
20.50 degrees --> (0, 39, 255)
20.75 degrees --> (0, 52, 255)
21.00 degrees --> (0, 65, 255)
21.25 degrees --> (0, 77, 255)
21.50 degrees --> (0, 90, 255)
21.75 degrees --> (0, 102, 255)
22.00 degrees --> (0, 115, 255)
22.25 degrees --> (0, 128, 255)
22.50 degrees --> (0, 140, 255)
22.75 degrees --> (0, 153, 255)
23.00 degrees --> (0, 166, 255)
23.25 degrees --> (0, 178, 255)
23.50 degrees --> (0, 191, 255)
23.75 degrees --> (0, 203, 255)
24.00 degrees --> (0, 216, 255)
24.25 degrees --> (0, 229, 255)
24.50 degrees --> (0, 241, 255)
24.75 degrees --> (0, 254, 255)
Last edited on
I went ahead and was able to do it with 1-d array but I can definitely see where a problem can occur if the values don't match exactly as the temperatures will come from a sensor

to be honest, this is a great perspective on solving this problem and I am just seeing why you mentioned to interpolate the values. This definitely works and is much more suitable than the idea that I thought of.

I will use this approach as a base for completing this part of my program.

I really do appreciate the help

Last edited on
there are a couple of other ways to do color.
for example if your do HSL, you can vary just the 'color' (hue) while maintaining brightness/levels.
I haven't used HSL in a while so I am unsure if you ran from blue to red (typical temp color scale) at your extremes if the middle would look right or not, but I seem to recall that it does pretty well for that (?).
The WinAPI has the COLORREF struct and several macro functions for dealing with RGB values at a basic level (0 - 255), usable in console mode code.

https://docs.microsoft.com/en-us/windows/win32/gdi/colorref
https://docs.microsoft.com/en-us/windows/win32/gdi/color-macros

Use the RGB macro to create a COLORREF from 3 discrete values, and the GetRValue, GetGValue, and GetBValue macros to get the individual RGB values as needed.
Topic archived. No new replies allowed.