cgv
Loading...
Searching...
No Matches
transfer_function.cxx
1#include "transfer_function.h"
2
3#include <cgv/media/ticks.h>
4#include <cgv/utils/algorithm.h>
5
6namespace cgv {
7namespace media {
8
9transfer_function::transfer_function(std::initializer_list<color_point_type> colors) {
10 set_color_points(colors);
11}
12
13transfer_function::transfer_function(std::initializer_list<color_point_type> colors, std::initializer_list<opacity_point_type> opacities) {
14 set_color_points(colors);
15 set_opacity_points(opacities);
16}
17
18void transfer_function::set_color_points(const std::vector<color_point_type>& colors) {
19 color_points_ = colors;
20 sort_points_and_update_domain(color_points_);
21 ensure_control_points_cover_domain(color_points_);
22 ensure_control_points_cover_domain(opacity_points_);
23}
24
26 std::vector<float> positions;
27 cgv::utils::subdivision_sequence(std::back_inserter(positions), 0.0f, 1.0f, n);
28 std::vector<cgv::rgb> colors = scheme.quantize(n);
29 set_color_points(cgv::utils::zip(positions.begin(), positions.end(), colors.begin()));
30}
31
32void transfer_function::set_opacity_points(const std::vector<opacity_point_type>& opacities) {
33 opacity_points_ = opacities;
34 std::for_each(opacity_points_.begin(), opacity_points_.end(), [](const opacity_point_type& point) { cgv::math::saturate(point.second); });
35 sort_points_and_update_domain(opacity_points_);
36 ensure_control_points_cover_domain(opacity_points_);
37 ensure_control_points_cover_domain(color_points_);
38}
39
42 color_points_.push_back({ x, color });
43 sort_points_and_update_domain(color_points_);
44 ensure_control_points_cover_domain(opacity_points_);
45}
46
47void transfer_function::add_opacity_point(float x, float opacity) {
49 opacity_points_.push_back({ x, cgv::math::saturate(opacity) });
50 sort_points_and_update_domain(opacity_points_);
51 ensure_control_points_cover_domain(color_points_);
52}
53
55 if(remove_point(color_points_, x)) {
56 modified();
57 return true;
58 }
59 return false;
60}
61
63 if(remove_point(opacity_points_, x)) {
64 modified();
65 return true;
66 }
67 return false;
68}
69
71 const vec2 current_domain = get_domain();
72
73 // Make sure we have points at either end of the new domain.
74 float lower_bound = current_domain[0] < domain[0] ? domain[0] : current_domain[0];
75 float upper_bound = current_domain[1] > domain[1] ? domain[1] : current_domain[1];
76
77 if(!color_points_.empty() && color_points_.front().first != lower_bound)
78 add_color_point(domain[0], get_mapped_color(lower_bound));
79 if(!opacity_points_.empty() && opacity_points_.front().first != lower_bound)
80 add_opacity_point(domain[0], get_mapped_opacity(lower_bound));
81
82 if(!color_points_.empty() && color_points_.back().first != upper_bound)
83 add_color_point(domain[1], get_mapped_color(upper_bound));
84 if(!opacity_points_.empty() && opacity_points_.back().first != upper_bound)
85 add_opacity_point(domain[1], get_mapped_opacity(upper_bound));
86
87 // Remove all points that are outside the new domain.
88 const auto is_point_out_of_range = [domain](const auto& point) {
89 return point.first < domain[0] || point.first > domain[1];
90 };
91
92 const auto remove_points_out_of_range = [domain, &is_point_out_of_range](auto& points) {
93 bool done = false;
94 bool removed = false;
95 while(!done) {
96 done = true;
97
98 auto it = std::find_if(points.begin(), points.end(), is_point_out_of_range);
99 if(it != points.end()) {
100 points.erase(it);
101 done = false;
102 removed = true;
103 }
104 }
105 return removed;
106 };
107
108 // Use temporary variables to ensure both functions are called which they otherwise may not due to short-circuit evaluation.
109 bool removed_color_points = remove_points_out_of_range(color_points_);
110 bool removed_opacity_points = remove_points_out_of_range(opacity_points_);
111 if(removed_color_points || removed_opacity_points)
112 modified();
113
114 sort_points_and_update_domain(color_points_);
115}
116
118 const cgv::vec2 current_domain = get_domain();
119
120 if(current_domain == domain)
121 return;
122
123 const auto map_point = [this, current_domain, domain](auto& point) {
124 point.first = map_range_safe(point.first, current_domain[0], current_domain[1], domain[0], domain[1]);
125 };
126
127 if(!color_points_.empty())
128 std::for_each(color_points_.begin(), color_points_.end(), map_point);
129
130 if(!opacity_points_.empty())
131 std::for_each(opacity_points_.begin(), opacity_points_.end(), map_point);
132
134}
135
136float transfer_function::normalize_value(float value) const {
137 const vec2 domain = get_domain();
138 value = cgv::math::clamp(value, domain[0], domain[1]);
139 return map_range_safe(value, domain[0], domain[1], 0.0f, 1.0f);
140}
141
144 float opacity = get_mapped_opacity(value);
145
146 return { color.R(), color.G(), color.B(), opacity };
147}
148
150 if(is_unknown(value) || color_points_.empty())
151 return get_unknown_color();
152 //const vec2 domain = get_domain();
153 //value = cgv::math::clamp(value, domain[0], domain[1]);
154 return interpolate(color_points_, value, color_interpolation_);
155}
156
158 if(opacity_points_.empty())
159 return 1.0f;
160 return interpolate(opacity_points_, value, opacity_interpolation_);
161}
162
163std::vector<cgv::rgba> transfer_function::quantize(size_t count) const {
164 const std::vector<cgv::rgb> colors = quantize_color(count);
165 const std::vector<float> opacities = quantize_opacity(count);
166
167 std::vector<cgv::rgba> values;
168 values.reserve(count);
169 std::transform(colors.begin(), colors.end(), opacities.begin(), std::back_inserter(values), [](const cgv::rgba& color, float opacity) {
170 return cgv::rgba(color, opacity);
171 });
172
173 return values;
174}
175
176std::vector<cgv::rgb> transfer_function::quantize_color(size_t count) const {
177 if(color_points_.empty())
178 return std::vector<cgv::rgb>(count, { 0.0f });
179
180 std::vector<cgv::rgb> colors = quantize(color_points_, count, color_interpolation_);
181 if(is_reversed())
182 std::reverse(colors.begin(), colors.end());
183 return colors;
184}
185
186std::vector<float> transfer_function::quantize_opacity(size_t count) const {
187 if(opacity_points_.empty())
188 return std::vector<float>(count, 1.0f);
189 std::vector<float> opacities = quantize(opacity_points_, count, opacity_interpolation_);
190 if(is_reversed())
191 std::reverse(opacities.begin(), opacities.end());
192 return opacities;
193}
194
195std::vector<float> transfer_function::get_ticks(size_t request_count) const {
196 /* This would return one tick for every color or opacity point.
197 std::vector<float> ticks;
198 if(!color_points_.empty())
199 std::transform(color_points_.begin(), color_points_.end(), std::back_inserter(ticks), cgv::utils::get_first<>{});// [] (const color_point_type& point))
200 else
201 std::transform(opacity_points_.begin(), opacity_points_.end(), std::back_inserter(ticks), cgv::utils::get_first<>{});
202 return ticks;
203 */
204 const vec2 domain = get_domain();
205 return compute_ticks(domain[0], domain[1], request_count);
206}
207
209 color_points_.clear();
210 opacity_points_.clear();
211 update_domain();
212}
213
215 color_points_.clear();
216 update_domain();
217}
218
220 opacity_points_.clear();
221 update_domain();
222}
223
225 if(color_interpolation_ != interpolation || opacity_interpolation_ != interpolation) {
226 color_interpolation_ = interpolation;
227 opacity_interpolation_ = interpolation;
228 modified();
229 }
230}
231
233 if(color_interpolation_ != interpolation) {
234 color_interpolation_ = interpolation;
235 modified();
236 }
237}
238
240 if(opacity_interpolation_ != interpolation) {
241 opacity_interpolation_ = interpolation;
242 modified();
243 }
244}
245
246bool transfer_function::update_domain() {
247 cgv::vec2 old_domain = get_domain();
248
249 cgv::vec2 domain = { 0.0f };
250 if(!color_points_.empty()) {
251 domain[0] = color_points_.front().first;
252 domain[1] = color_points_.back().first;
253 }
254 if(!opacity_points_.empty()) {
255 domain[0] = std::min(domain[0], opacity_points_.front().first);
256 domain[1] = std::max(domain[1], opacity_points_.back().first);
257 }
258
259 if(old_domain != domain) {
261 return true;
262 }
263 return false;
264}
265
266} // namespace media
267} // 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
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.
virtual void set_domain(cgv::vec2 domain)
Set the input domain of scalars that will be mapped.
This class represents a continuous color scheme using an interpolator to convert continuous scalar va...
std::vector< cgv::rgb > quantize(size_t n) const
Evaluate the color scheme at n uniformly-spaced positions within the range [0,1].
void clear()
Clear all color and opacity control points.
float normalize_value(float value) const override
See color_scale::normalize_value().
float get_mapped_opacity(float value) const override
See color_scale::get_mapped_opacity().
bool remove_opacity_point(float x)
Remove the opacity point at position x if it exists.
InterpolationMode
The interpolation modes supported by the transfer function.
void add_color_point(float x, const color_type &color)
Add a color point at position x.
void set_opacity_points(const std::vector< opacity_point_type > &opacities)
Set the opacity function to use the given control points.
void clear_opacity_points()
Clear opacity control points only.
bool remove_color_point(float x)
Remove the color point at position x if it exists.
std::pair< float, opacity_type > opacity_point_type
The used opacity control point type.
void set_color_points(const std::vector< color_point_type > &colors)
Set the color function to use the given control points.
transfer_function()
Construct using default arguments.
std::vector< float > get_ticks(size_t request_count) const override
See color_scale::get_ticks().
void add_opacity_point(float x, float opacity)
Add an opacity point at position x.
std::vector< cgv::rgb > quantize_color(size_t count) const
Quantize the color function only.
void set_interpolation(InterpolationMode interpolation)
Set the interpolation mode of the color and opacity function.
InterpolationMode set_opacity_interpolation() const
Get the interpolation mode of the opacity function.
void set_color_interpolation(InterpolationMode interpolation)
Set the interpolation mode of the color function.
cgv::rgba map_value(float value) const override
See color_scale::map_value().
void set_color_points_from_scheme(const cgv::media::continuous_color_scheme &scheme, size_t n)
Set the color function to use n uniformly sampled points from the given color scheme.
std::vector< cgv::rgba > quantize(size_t count) const override
See color_scale::quantize().
void rescale(cgv::vec2 domain)
Rescale the color and opactiy functions to the new domain.
std::vector< float > quantize_opacity(size_t count) const
Quantize the opacity function only.
void set_domain(cgv::vec2 domain) override
Set the domain.
cgv::rgb get_mapped_color(float value) const override
See color_scale::get_mapped_color().
void clear_color_points()
Clear color control points only.
OutputIt zip(const InputIt1 first1, const InputIt1 last1, const InputIt2 first2, OutputIt d_first)
Zip two sequences together to form a single sequene of pairs and store the results in an output range...
Definition algorithm.h:199
void subdivision_sequence(OutputIt output_first, ParamT start, ParamT stop, size_t n)
Generate a sequence of n uniformly-spaced values in [start,stop] and store the result in an output ra...
Definition algorithm.h:233
this header is dependency free
Definition print.h:11
T B() const
convert color to RGB and return B component
Definition color.h:418
T R() const
convert color to RGB and return R component
Definition color.h:414
T G() const
convert color to RGB and return G component
Definition color.h:416