GCC Code Coverage Report


./
File: libs/__/data/transfer_function.cpp
Date: 2025-01-21 16:21:04
Lines:
205/210
97.6%
Functions:
24/24
100.0%
Branches:
121/293
41.3%

Line Branch Exec Source
1 /************************************************************************
2 *
3 * Copyright (C) 2009-2024 IRCAD France
4 * Copyright (C) 2012-2020 IHU Strasbourg
5 *
6 * This file is part of Sight.
7 *
8 * Sight is free software: you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * Sight is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with Sight. If not, see <https://www.gnu.org/licenses/>.
20 *
21 ***********************************************************************/
22
23 #include "data/transfer_function.hpp"
24
25 #include "data/exception.hpp"
26 #include "data/registry/macros.hpp"
27
28 #include <core/com/signal.hxx>
29 #include <core/type.hpp>
30
31 #include <glm/common.hpp>
32
33 SIGHT_REGISTER_DATA(sight::data::transfer_function)
34
35 namespace sight::data
36 {
37
38 //------------------------------------------------------------------------------
39
40 const std::string transfer_function::DEFAULT_TF_NAME = "GreyLevel";
41
42 const core::com::signals::key_t transfer_function::POINTS_MODIFIED_SIG = "pointsModified";
43 const core::com::signals::key_t transfer_function::WINDOWING_MODIFIED_SIG = "windowingModified";
44
45 //------------------------------------------------------------------------------
46
47 355 transfer_function_base::value_t transfer_function_base::map_value_to_window(value_t _value) const
48 {
49 355 const min_max_t min_max = this->min_max();
50 355 const min_max_t window_min_max = this->window_min_max();
51
52 355 const value_t scale = window() / (min_max.second - min_max.first);
53 355 const value_t value = (_value - min_max.first) * scale + window_min_max.first;
54
55 355 return value;
56 }
57
58 //------------------------------------------------------------------------------
59
60 35844 transfer_function_base::value_t transfer_function_base::map_value_from_window(value_t _value) const
61 {
62 35844 const min_max_t min_max = this->min_max();
63 35844 const min_max_t window_min_max = this->window_min_max();
64
65 35844 const value_t scale = (min_max.second - min_max.first) / window();
66 35844 const value_t value = (_value - window_min_max.first) * scale + min_max.first;
67
68 35844 return value;
69 }
70
71 //------------------------------------------------------------------------------
72
73 39 transfer_function_base::color_t transfer_function_base::sample_nearest(value_t _value) const
74 {
75 39 return sample(_value, interpolation_mode::nearest);
76 }
77
78 //------------------------------------------------------------------------------
79
80 47 transfer_function_base::color_t transfer_function_base::sample_linear(value_t _value) const
81 {
82 47 return sample(_value, interpolation_mode::linear);
83 }
84
85 //------------------------------------------------------------------------------
86
87 36263 transfer_function_piece::min_max_t transfer_function_base::window_min_max() const
88 {
89 36263 min_max_t min_max;
90 36263 const value_t half_window = this->window() / 2.;
91
92 36263 const value_t level = this->level();
93 36263 min_max.first = level - half_window;
94 36263 min_max.second = level + half_window;
95 36263 return min_max;
96 }
97
98 //------------------------------------------------------------------------------
99
100 14 void transfer_function_base::set_window_min_max(const min_max_t& _min_max)
101 {
102 14 this->set_window(
103 14 _min_max.second
104
2/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
28 >= _min_max.first ? std::max(1., _min_max.second - _min_max.first) : std::min(
105 14 -1.,
106 _min_max.second - _min_max.first
107 )
108 );
109
110 14 const value_t half_window = window() * 0.5;
111 14 this->set_level(half_window + _min_max.first);
112 14 }
113
114 //------------------------------------------------------------------------------
115 //------------------------------------------------------------------------------
116 //------------------------------------------------------------------------------
117
118 36360 transfer_function_piece::min_max_t transfer_function_piece::min_max() const
119 {
120 36360 SIGHT_ASSERT("It must have at least one value.", !this->empty());
121 36360 min_max_t min_max;
122 36360 min_max.first = this->begin()->first;
123 36360 min_max.second = (this->rbegin())->first;
124 36360 return min_max;
125 }
126
127 //------------------------------------------------------------------------------
128
129 35837 transfer_function_piece::color_t transfer_function_piece::sample(
130 value_t _value,
131 std::optional<enum interpolation_mode> _mode
132 ) const
133 {
134 35837 SIGHT_ASSERT("It must have at least one value.", !empty());
135
136 35837 const value_t value = this->map_value_from_window(_value);
137
138 35837 const color_t black_color(0.0);
139
140 35837 value_t previous_value = value;
141
2/2
✓ Branch 0 taken 35754 times.
✓ Branch 1 taken 83 times.
35837 color_t previous_color = m_clamped ? black_color : this->begin()->second;
142
143 35837 value_t next_value = value;
144
2/2
✓ Branch 0 taken 35754 times.
✓ Branch 1 taken 83 times.
35837 color_t next_color = m_clamped ? black_color : this->rbegin()->second;
145
146 35837 color_t color(0.0);
147
148 35837 bool found = false;
149
2/2
✓ Branch 0 taken 86883 times.
✓ Branch 1 taken 369 times.
87252 for(const auto& data : *this)
150 {
151 86883 next_value = data.first;
152 86883 next_color = data.second;
153
154
2/2
✓ Branch 0 taken 51415 times.
✓ Branch 1 taken 35468 times.
86883 if(value < data.first)
155 {
156 found = true;
157 break;
158 }
159
160 51415 previous_value = next_value;
161 51415 previous_color = next_color;
162 }
163
164
2/2
✓ Branch 0 taken 369 times.
✓ Branch 1 taken 35468 times.
35837 if(!found)
165 {
166 369 next_value = value;
167
2/2
✓ Branch 0 taken 348 times.
✓ Branch 1 taken 21 times.
369 next_color = m_clamped ? black_color : this->rbegin()->second;
168 }
169
170
2/2
✓ Branch 0 taken 35751 times.
✓ Branch 1 taken 86 times.
35837 const enum interpolation_mode mode = _mode == std::nullopt ? m_interpolation_mode : _mode.value();
171
2/3
✓ Branch 0 taken 19398 times.
✓ Branch 1 taken 16439 times.
✗ Branch 2 not taken.
35837 switch(mode)
172 {
173 19398 case transfer_function_piece::interpolation_mode::linear:
174 19398 {
175 19398 const value_t distance = next_value - previous_value;
176
2/2
✓ Branch 0 taken 19358 times.
✓ Branch 1 taken 40 times.
19398 const value_t interpolant = distance < 1e-5 ? 0. : (value - previous_value) / distance;
177 19398 color = glm::mix(previous_color, next_color, interpolant);
178 break;
179 }
180
181 16439 case transfer_function_piece::interpolation_mode::nearest:
182 16439 {
183
2/2
✓ Branch 0 taken 8230 times.
✓ Branch 1 taken 8209 times.
16439 if((value - previous_value) <= (next_value - value))
184 {
185 8230 color = previous_color;
186 }
187 else
188 {
189 8209 color = next_color;
190 }
191
192 break;
193 }
194
195 35837 default:
196 35837 SIGHT_ASSERT("Unreachable code, undefined interpolation mode", false);
197 }
198
199 35837 return color;
200 }
201
202 //-----------------------------------------------------------------------------
203
204 166 void transfer_function_piece::set_level(transfer_function_piece::value_t _value)
205 {
206 166 m_level = _value;
207 166 }
208
209 //-----------------------------------------------------------------------------
210
211 165 void transfer_function_piece::set_window(transfer_function_piece::value_t _value)
212 {
213 165 m_window = _value;
214 165 }
215
216 //------------------------------------------------------------------------------
217 //------------------------------------------------------------------------------
218 //------------------------------------------------------------------------------
219
220 14 data::transfer_function::sptr transfer_function::create_default_tf()
221 {
222 14 transfer_function::sptr tf = std::make_shared<transfer_function>();
223
224
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 tf->set_name(transfer_function::DEFAULT_TF_NAME);
225
226
4/10
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 14 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
28 auto tf_data = tf->pieces().emplace_back(std::make_shared<data::transfer_function_piece>());
227
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 tf_data->insert({0.0, color_t()});
228
1/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
14 tf_data->insert({1.0, color_t(1.0, 1.0, 1.0, 1.0)});
229
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 tf_data->set_clamped(false);
230
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 tf_data->set_window(500.);
231
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 tf_data->set_level(50.);
232
233
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 tf->fit_window();
234
235
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 return tf;
236 14 }
237
238 //------------------------------------------------------------------------------
239
240 14 data::transfer_function::sptr transfer_function::create_default_tf(core::type _type)
241 {
242 14 transfer_function::sptr tf = std::make_shared<transfer_function>();
243
244
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 tf->set_name(transfer_function::DEFAULT_TF_NAME);
245
246
4/10
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 14 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
28 auto tf_data = tf->pieces().emplace_back(std::make_shared<data::transfer_function_piece>());
247
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 tf_data->insert({0.0, color_t()});
248
1/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
14 tf_data->insert({1.0, color_t(1.0, 1.0, 1.0, 1.0)});
249
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 tf_data->set_clamped(false);
250
2/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
14 if(_type == core::type::INT8 || _type == core::type::UINT8)
251 {
252 tf_data->set_window(255.);
253 tf_data->set_level(127.);
254 }
255 else
256 {
257
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 tf_data->set_window(500.);
258
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 tf_data->set_level(50.);
259 }
260
261
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 tf->fit_window();
262
263
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 return tf;
264 14 }
265
266 //------------------------------------------------------------------------------
267
268
1/2
✓ Branch 2 taken 334 times.
✗ Branch 3 not taken.
334 transfer_function::transfer_function()
269 {
270
1/2
✓ Branch 1 taken 334 times.
✗ Branch 2 not taken.
334 new_signal<points_modified_signal_t>(POINTS_MODIFIED_SIG);
271
1/2
✓ Branch 1 taken 334 times.
✗ Branch 2 not taken.
334 new_signal<windowing_modified_signal_t>(WINDOWING_MODIFIED_SIG);
272 334 }
273
274 //------------------------------------------------------------------------------
275
276 114 void transfer_function::shallow_copy(const object::csptr& _source)
277 {
278 114 const auto& other = std::dynamic_pointer_cast<const transfer_function>(_source);
279
280
1/46
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
114 SIGHT_THROW_EXCEPTION_IF(
281 exception(
282 "Unable to copy " + (_source ? _source->get_classname() : std::string("<NULL>"))
283 + " to " + get_classname()
284 ),
285 !bool(other)
286 );
287
288
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 m_name = other->m_name;
289 114 m_background_color = other->m_background_color;
290
291 114 m_level = other->m_level;
292 114 m_window = other->m_window;
293
294 114 m_pieces.clear();
295
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 std::ranges::copy(other->m_pieces, std::back_inserter(m_pieces));
296
297
3/8
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 114 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 114 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
342 base_class_t::shallow_copy(other);
298 114 }
299
300 //------------------------------------------------------------------------------
301
302 153 void transfer_function::deep_copy(const object::csptr& _source, const std::unique_ptr<deep_copy_cache_t>& _cache)
303 {
304 153 const auto& other = std::dynamic_pointer_cast<const transfer_function>(_source);
305
306
1/46
✗ Branch 0 not taken.
✓ Branch 1 taken 153 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
153 SIGHT_THROW_EXCEPTION_IF(
307 data::exception(
308 "Unable to copy " + (_source ? _source->get_classname() : std::string("<NULL>"))
309 + " to " + get_classname()
310 ),
311 !bool(other)
312 );
313
314
1/2
✓ Branch 1 taken 153 times.
✗ Branch 2 not taken.
153 m_name = other->m_name;
315 153 m_background_color = other->m_background_color;
316
317 153 m_level = other->m_level;
318 153 m_window = other->m_window;
319
320 153 m_pieces.clear();
321
322 153 std::ranges::transform(
323
1/2
✓ Branch 1 taken 153 times.
✗ Branch 2 not taken.
153 other->m_pieces,
324
1/2
✓ Branch 1 taken 153 times.
✗ Branch 2 not taken.
153 std::back_inserter(this->m_pieces),
325 149 [&](const auto& _value)
326 {
327
1/2
✓ Branch 1 taken 149 times.
✗ Branch 2 not taken.
149 auto data = std::make_shared<transfer_function_piece>();
328
1/2
✓ Branch 1 taken 149 times.
✗ Branch 2 not taken.
149 *data = *_value;
329 149 return data;
330 });
331
332
3/8
✓ Branch 0 taken 153 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 153 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 153 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
459 base_class_t::deep_copy(other, _cache);
333 153 }
334
335 //------------------------------------------------------------------------------
336
337 24 bool transfer_function::operator==(const transfer_function& _other) const noexcept
338 {
339 24 if(m_name != _other.m_name
340
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
22 || !core::is_equal(m_background_color, _other.m_background_color)
341
4/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 17 times.
44 || m_pieces.size() != _other.m_pieces.size())
342 {
343 return false;
344 }
345
346 // test each piece in m_pieces
347
348
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 17 times.
26 auto a_it = m_pieces.cbegin();
349 26 auto b_it = _other.m_pieces.cbegin();
350
351
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 17 times.
26 const auto a_end = m_pieces.cend();
352
353
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 17 times.
26 while(a_it != a_end)
354 {
355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if(**a_it != **b_it)
356 {
357 return false;
358 }
359
360 9 ++a_it;
361 9 ++b_it;
362 }
363
364 // Super class last
365 17 return base_class_t::operator==(_other);
366 }
367
368 //------------------------------------------------------------------------------
369
370 8 bool transfer_function::operator!=(const transfer_function& _other) const noexcept
371 {
372 8 return !(*this == _other);
373 }
374
375 //-----------------------------------------------------------------------------
376
377 142 void transfer_function::fit_window()
378 {
379 142 min_max_t min_max {std::numeric_limits<value_t>::max(), std::numeric_limits<value_t>::lowest()};
380
381
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 142 times.
285 for(auto& piece : this->pieces())
382 {
383
1/2
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
143 const auto piece_min_max = piece->min_max();
384
3/4
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 142 times.
143 min_max.first = std::min(piece->map_value_to_window(piece_min_max.first), min_max.first);
385
2/4
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 143 times.
143 min_max.second = std::max(piece->map_value_to_window(piece_min_max.second), min_max.second);
386 }
387
388 // Updates the window/level.
389 142 m_window = min_max.second - min_max.first;
390 142 m_level = min_max.first + m_window * .5;
391 142 }
392
393 //------------------------------------------------------------------------------
394
395 24 void transfer_function::set_level(value_t _value)
396 {
397 24 const double delta = _value - this->level();
398
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 24 times.
30 for(auto& piece : this->pieces())
399 {
400 6 piece->set_level(piece->level() + delta);
401 }
402
403 24 m_level = _value;
404 24 }
405
406 //-----------------------------------------------------------------------------
407
408 23 void transfer_function::set_window(value_t _value)
409 {
410 23 SIGHT_ASSERT("Window should be non-null", std::fpclassify(_value) != FP_ZERO);
411
412 23 const double scale = _value / this->window();
413
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 23 times.
28 for(auto& piece : this->pieces())
414 {
415 5 piece->set_window(piece->window() * scale);
416 }
417
418 23 m_window = _value;
419 23 }
420
421 //------------------------------------------------------------------------------
422
423 7 transfer_function_piece::min_max_t transfer_function::min_max() const
424 {
425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if(empty())
426 {
427 return {-1., 1.};
428 }
429
430 7 min_max_t min_max {std::numeric_limits<value_t>::max(), std::numeric_limits<value_t>::lowest()};
431
432
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 for(const auto& piece : this->pieces())
433 {
434
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 const auto piece_min_max = piece->min_max();
435
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
7 min_max.first = std::min(piece->map_value_to_window(piece_min_max.first), min_max.first);
436
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
7 min_max.second = std::max(piece->map_value_to_window(piece_min_max.second), min_max.second);
437 }
438
439 7 return min_max;
440 }
441
442 //------------------------------------------------------------------------------
443
444 35069 transfer_function_piece::color_t transfer_function::sample(
445 value_t _value,
446 std::optional<interpolation_mode> _mode
447 ) const
448 {
449 35069 SIGHT_ASSERT("It must have at least one value.", !empty());
450
451 35069 transfer_function_base::color_t result(0.);
452 35069 std::vector<transfer_function_base::color_t> colors;
453
1/2
✓ Branch 1 taken 35069 times.
✗ Branch 2 not taken.
35069 colors.reserve(this->pieces().size());
454
455 // 1. Determine the maximum of opacity for this value
456
2/2
✓ Branch 0 taken 35074 times.
✓ Branch 1 taken 35069 times.
70143 for(const auto& piece : this->pieces())
457 {
458
1/2
✓ Branch 1 taken 35074 times.
✗ Branch 2 not taken.
35074 transfer_function_base::color_t color = piece->sample(_value, _mode);
459
2/2
✓ Branch 0 taken 22716 times.
✓ Branch 1 taken 12358 times.
35074 result.a = std::max(result.a, color.a);
460
1/2
✓ Branch 1 taken 35074 times.
✗ Branch 2 not taken.
35074 colors.push_back(color);
461 }
462
463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35069 times.
35069 result.a = std::min(result.a, 1.);
464
465 // 2. Mix the colors by the ratio of the opacity and the maximum opacity
466
2/2
✓ Branch 0 taken 35074 times.
✓ Branch 1 taken 35069 times.
70143 for(const auto& color : colors)
467 {
468
2/2
✓ Branch 0 taken 22720 times.
✓ Branch 1 taken 12354 times.
35074 const double ratio = result.a == 0. ? 1.0 : color.a / result.a;
469 35074 result.r += color.r * ratio;
470 35074 result.g += color.g * ratio;
471 35074 result.b += color.b * ratio;
472 }
473
474
1/2
✓ Branch 1 taken 35069 times.
✗ Branch 2 not taken.
70138 return glm::min(result, glm::dvec4(1.));
475 35069 }
476
477 //------------------------------------------------------------------------------
478
479 2 void transfer_function::merge(sight::data::transfer_function& _dst, const sight::data::transfer_function& _src)
480 {
481
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 for(auto& dst_pieces = _dst.pieces() ; const auto& piece : _src.pieces())
482 {
483 3 SIGHT_ASSERT("Invalid transfer function", piece != nullptr);
484
485 // Include only if not already existing in the destination
486
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if(not std::ranges::any_of(
487 dst_pieces,
488
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 [&piece](const auto& _p) noexcept {return *_p == *piece;}))
489 {
490
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 auto copy = sight::data::transfer_function_piece::make();
491
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 *copy = *piece;
492
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 dst_pieces.emplace_back(std::move(copy));
493 1 }
494 }
495 2 }
496
497 } // end namespace sight::data
498