cgv
Loading...
Searching...
No Matches
color_scale.cxx
1#include "color_scale.h"
2
3#include <cgv/math/compare_float.h>
4#include <cgv/media/ticks.h>
5
6namespace cgv {
7namespace media {
8
10 domain_ = domain;
11 modified();
12}
13
14void color_scale::set_clamped(bool clamped) {
15 if(is_clamped_ != clamped) {
16 is_clamped_ = clamped;
17 modified();
18 }
19}
20
21void color_scale::set_reversed(bool reverse) {
22 if(is_reversed_ != reverse) {
23 is_reversed_ = reverse;
24 modified();
25 }
26}
27
28bool color_scale::is_unknown(float value) const {
29 const vec2 domain = get_domain();
30 return !is_clamped() && (value < domain[0] || value > domain[1]);
31}
32
33float color_scale::map_range_safe(float value, float in_left, float in_right, float out_left, float out_right) const {
34 float size = in_right - in_left;
35 if(cgv::math::is_zero(size))
36 return out_left;
37 return out_left + (out_right - out_left) * ((value - in_left) / size);
38}
39
42 update_log_invariants();
43}
44
45void continuous_color_scale::set_transform(ContinuousMappingTransform transform) {
46 mapping_transform_ = transform;
47 update_log_invariants();
48 modified();
49}
50
52 if(pow_exponent_ != exponent) {
53 pow_exponent_ = exponent;
54 modified();
55 }
56}
57
59 if(log_base_ != base) {
60 log_base_ = base;
61 update_log_invariants();
62 modified();
63 }
64}
65
67 if(is_diverging_ != diverging) {
68 is_diverging_ = diverging;
69 modified();
70 }
71}
72
74 if(diverging_midpoint_ != midpoint) {
75 diverging_midpoint_ = midpoint;
76 modified();
77 }
78}
79
81 // Clamp the input value to the domain if requested.
82 const cgv::vec2 domain = get_domain();
83 if(is_clamped())
84 value = cgv::math::clamp(value, domain[0], domain[1]);
85
86 float t = 0.0f;
87
88 // Map the value fromt he input domain to [0,1] while applying the set transform.
89 // Diverging scales split the domain at the midpoint into a lower [domain[0], midpoint] and upper part [midpoint, domain[1]].
90 // The lower part uses a reversed transform.
91 switch(mapping_transform_) {
92 case ContinuousMappingTransform::kLinear:
93 if(is_diverging_) {
94 if(value < diverging_midpoint_)
95 t = map_range_safe(value, domain[0], diverging_midpoint_, 0.0f, 0.5f);
96 else
97 t = map_range_safe(value, diverging_midpoint_, domain[1], 0.5f, 1.0f);
98 } else {
99 t = map_range_safe(value, domain[0], domain[1], 0.0f, 1.0f);
100 }
101 break;
102 case ContinuousMappingTransform::kPow:
103 if(is_diverging_) {
104 if(value < diverging_midpoint_) {
105 t = map_range_safe(value, domain[0], diverging_midpoint_, 0.0f, 1.0f);
106 t = 0.5f * (1.0f - std::pow(1.0f - t, pow_exponent_));
107 } else {
108 t = map_range_safe(value, diverging_midpoint_, domain[1], 0.0f, 1.0f);
109 t = 0.5f * std::pow(t, pow_exponent_) + 0.5f;
110 }
111 } else {
112 t = map_range_safe(value, domain[0], domain[1], 0.0f, 1.0f);
113 t = std::pow(t, pow_exponent_);
114 }
115 break;
116 case ContinuousMappingTransform::kLog:
117 t = std::log(log_value_sign_ * value) / log_of_base_;
118 if(is_diverging_) {
119 if(value < diverging_midpoint_) {
120 t = map_range_safe(t, log_of_lower_bound_, log_of_midpoint_, 0.0f, 0.5f);
121 } else {
122 t = map_range_safe(t, log_of_midpoint_, log_of_upper_bound_, 0.5f, 1.0f);
123 }
124 } else {
125 t = map_range_safe(t, log_of_lower_bound_, log_of_upper_bound_, 0.0f, 1.0f);
126 }
127 if(std::isnan(t))
128 t = 0.0f;
129 t *= log_value_sign_;
130 break;
131 default:
132 break;
133 }
134
135 return is_reversed() ? 1.0f - t : t;
136}
137
139 if(is_unknown(value))
140 return { get_unknown_color(), 1.0f };
141 return scheme_.interpolate(normalize_value(value));
142}
143
144std::vector<cgv::rgba> continuous_color_scale::quantize(size_t count) const {
145 std::vector<cgv::rgba> colors;
146 colors.reserve(count);
147 cgv::vec2 domain = { 0.0f, 1.0f };
148 if(is_reversed())
149 std::swap(domain[0], domain[1]);
150 cgv::math::sequence_transform(std::back_inserter(colors), [this](float t) { return scheme_.get_interpolator()->at(t); }, count, domain[0], domain[1]);
151 return colors;
152}
153
154std::vector<float> continuous_color_scale::get_ticks(size_t request_count) const {
155 const vec2 domain = get_domain();
156
157 if(mapping_transform_ == ContinuousMappingTransform::kLog)
158 return compute_ticks_log(domain[0], domain[1], log_base_, request_count);
159 else
160 return compute_ticks(domain[0], domain[1], request_count);
161}
162
164 scheme_ = scheme;
165 modified();
166}
167
168void continuous_color_scale::update_log_invariants() {
169 if(mapping_transform_ == ContinuousMappingTransform::kLog) {
170 vec2 domain = get_domain();
171
172 if(domain[0] < 0.0f && domain[1] < 0.0f)
173 log_value_sign_ = -1.0f;
174
175 log_of_base_ = std::log(log_base_);
176 log_of_midpoint_ = std::log(log_value_sign_ * diverging_midpoint_) / log_of_base_;
177 log_of_lower_bound_ = std::log(log_value_sign_ * domain[0]) / log_of_base_;
178 log_of_upper_bound_ = std::log(log_value_sign_ * domain[1]) / log_of_base_;
179 }
180}
181
183 cgv::vec2 domain = get_domain();
184 if(is_clamped())
185 value = cgv::math::clamp(value, domain[0], domain[1]);
186
187 return map_range_safe(value, domain[0], domain[1], 0.0f, 1.0f);
188}
189
191 if(is_unknown(value) || colors_.empty())
192 return { get_unknown_color(), 1.0f };
193
194 float t = normalize_value(value);
195
196 if(t <= 0.0f)
197 return colors_.front();
198 else if(t >= 1.0f)
199 return colors_.back();
200 else
201 return colors_[std::min(static_cast<size_t>(std::floor(t * static_cast<float>(colors_.size()))), colors_.size() - 1)];
202}
203
205 index %= colors_.size();
206 return { colors_[index], 1.0f };
207}
208
209std::vector<cgv::rgba> discrete_color_scale::quantize(size_t count) const {
210 std::vector<cgv::rgba> colors;
211 size_t color_count = get_indexed_color_count();
212 for(size_t i = 0; i < color_count; ++i) {
213 size_t index = is_reversed() ? color_count - i - 1 : i;
214 colors.push_back(colors_[index]);
215 }
216 return colors;
217}
218
219std::vector<float> discrete_color_scale::get_ticks(size_t request_count) const {
220 return {};
221}
222
224 colors_ = scheme.get_colors(size);
225 modified();
226}
227
228} // namespace media
229} // namespace cgv
bool is_unknown(float value) const
Test whether the value is outside the domain according to the mapping options.
float map_range_safe(float value, float in_left, float in_right, float out_left, float out_right) const
Remap a scalar value from an input range to and output range while safely handling empty ranges.
bool is_reversed() const
Get whether the output color ramp is reversed.
Definition color_scale.h:76
virtual void set_reversed(bool reverse)
Set whether the output color ramp is reversed.
cgv::rgba get_unknown_color() const
Get the color returned for scalars outside the domain if clamping is disabled.
Definition color_scale.h:93
cgv::vec2 get_domain() const
Get the input domain of scalars that will be mapped.
Definition color_scale.h:52
void modified()
Update the object's modified time.
bool is_clamped() const
Get whether the input values are clamped to the domain before mapping.
Definition color_scale.h:64
virtual void set_domain(cgv::vec2 domain)
Set the input domain of scalars that will be mapped.
virtual void set_clamped(bool clamped)
Set whether the input values are clamped to the domain before mapping.
std::vector< float > get_ticks(size_t request_count) const override
See color_scale::get_ticks().
std::vector< cgv::rgba > quantize(size_t count) const override
See color_scale::quantize().
cgv::rgb get_mapped_color(float value) const override
See color_scale::get_mapped_value()
float normalize_value(float value) const override
See color_scale::normalize_value()
virtual void set_midpoint(float midpoint)
Set the midpoint for diverging scales.
virtual void set_diverging(bool diverging)
Set whether the scale uses a diverging mapping.
virtual void set_log_base(float base)
Set the base for logarithmic scales.
virtual void set_pow_exponent(float exponent)
Set the exponent for power scales.
void set_transform(ContinuousMappingTransform transform)
Set the transform used to map scalars to colors.
void set_domain(cgv::vec2 domain) override
See color_scale::set_domain().
void set_scheme(const continuous_color_scheme &scheme)
Set the color scheme used as this scale's color ramp.
This class represents a continuous color scheme using an interpolator to convert continuous scalar va...
std::shared_ptr< const interpolator_type > get_interpolator() const
Return the interpolator.
cgv::rgb interpolate(float t) const
Evaluate the color scheme at position t.
cgv::rgb get_mapped_color(float value) const override
Map a value through the scale and return a RGB color.
std::vector< float > get_ticks(size_t request_count) const override
Not implemented for discrete color scales.
void set_scheme(const discrete_color_scheme &scheme, size_t size)
Set the color scheme and size used as this scale's indexed color source.
cgv::rgba get_indexed_color(size_t index) const override
Return the RGBA color with the given index.
std::vector< cgv::rgba > quantize(size_t count) const override
Return a sequence of all indexed colors, ignoring count.
float normalize_value(float value) const override
See color_scale::normalize_value().
size_t get_indexed_color_count() const override
See color_scale::get_indexed_color_count().
This class represents a discrete color scheme using sets of colors to convert discrete scalars to col...
const std::vector< cgv::rgb > get_colors(size_t n) const
Return a sequence of colors of the specified count.
this header is dependency free
Definition print.h:11