Line |
Branch |
Exec |
Source |
1 |
|
|
/************************************************************************ |
2 |
|
|
* |
3 |
|
|
* Copyright (C) 2014-2025 IRCAD France |
4 |
|
|
* Copyright (C) 2014-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 |
|
|
// cspell:ignore NOLINTNEXTLINE NOLINT |
24 |
|
|
|
25 |
|
|
#include "modules/viz/scene3d/adaptor/negato3d.hpp" |
26 |
|
|
|
27 |
|
|
#include <core/com/signal.hxx> |
28 |
|
|
#include <core/com/slots.hxx> |
29 |
|
|
|
30 |
|
|
#include <data/boolean.hpp> |
31 |
|
|
#include <data/helper/medical_image.hpp> |
32 |
|
|
#include <data/image.hpp> |
33 |
|
|
#include <data/tools/color.hpp> |
34 |
|
|
|
35 |
|
|
#include <geometry/data/image.hpp> |
36 |
|
|
|
37 |
|
|
#include <viz/scene3d/ogre.hpp> |
38 |
|
|
#include <viz/scene3d/utils.hpp> |
39 |
|
|
|
40 |
|
|
#include <OGRE/OgreCamera.h> |
41 |
|
|
#include <OGRE/OgreSceneNode.h> |
42 |
|
|
#include <OGRE/OgreVector.h> |
43 |
|
|
|
44 |
|
|
#include <algorithm> |
45 |
|
|
|
46 |
|
|
namespace sight::module::viz::scene3d::adaptor |
47 |
|
|
{ |
48 |
|
|
|
49 |
|
|
//------------------------------------------------------------------------------ |
50 |
|
|
|
51 |
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
|
18 |
negato3d::negato3d() noexcept |
52 |
|
|
{ |
53 |
|
|
// Auto-connected slots |
54 |
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 |
new_slot(slots::UPDATE_IMAGE, [this](){lazy_update(update_flags::IMAGE);}); |
55 |
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 |
new_slot(slots::UPDATE_TF, [this](){lazy_update(update_flags::TF);}); |
56 |
|
|
|
57 |
|
|
// Interaction slots |
58 |
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 |
new_slot(slots::SLICE_TYPE, &negato3d::change_slice_type, this); |
59 |
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 |
new_slot(slots::SLICE_INDEX, &negato3d::change_slice_index, this); |
60 |
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 |
new_slot(slots::UPDATE_SLICES_FROM_WORLD, &negato3d::update_slices_from_world, this); |
61 |
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 |
new_slot(slots::SET_TRANSPARENCY, &negato3d::set_transparency, this); |
62 |
|
|
|
63 |
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 |
new_signal<signals::picked_voxel_t>(signals::PICKED_VOXEL); |
64 |
|
18 |
} |
65 |
|
|
|
66 |
|
|
//------------------------------------------------------------------------------ |
67 |
|
|
|
68 |
|
7 |
void negato3d::configuring() |
69 |
|
|
{ |
70 |
|
7 |
this->configure_params(); |
71 |
|
|
|
72 |
|
7 |
const config_t config = this->get_config(); |
73 |
|
|
|
74 |
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
7 |
static const std::string s_AUTORESET_CAMERA_CONFIG = CONFIG + "autoresetcamera"; |
75 |
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
7 |
static const std::string s_FILTERING_CONFIG = CONFIG + "filtering"; |
76 |
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
7 |
static const std::string s_TF_ALPHA_CONFIG = CONFIG + "tfAlpha"; |
77 |
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
7 |
static const std::string s_INTERACTIVE_CONFIG = CONFIG + "interactive"; |
78 |
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
7 |
static const std::string s_PRIORITY_CONFIG = CONFIG + "priority"; |
79 |
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
7 |
static const std::string s_QUERY_CONFIG = CONFIG + "queryFlags"; |
80 |
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
7 |
static const std::string s_BORDER_CONFIG = CONFIG + "border"; |
81 |
|
|
|
82 |
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
21 |
m_auto_reset_camera = config.get<bool>(s_AUTORESET_CAMERA_CONFIG, true); |
83 |
|
|
|
84 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 |
if(config.count(s_FILTERING_CONFIG) != 0U) |
85 |
|
|
{ |
86 |
|
✗ |
const auto filtering_value = config.get<std::string>(s_FILTERING_CONFIG); |
87 |
|
✗ |
sight::viz::scene3d::plane::filter_t filtering(sight::viz::scene3d::plane::filter_t::linear); |
88 |
|
|
|
89 |
|
✗ |
if(filtering_value == "none") |
90 |
|
|
{ |
91 |
|
|
filtering = sight::viz::scene3d::plane::filter_t::none; |
92 |
|
|
} |
93 |
|
✗ |
else if(filtering_value == "anisotropic") |
94 |
|
|
{ |
95 |
|
✗ |
filtering = sight::viz::scene3d::plane::filter_t::anisotropic; |
96 |
|
|
} |
97 |
|
|
|
98 |
|
✗ |
m_filtering = filtering; |
99 |
|
|
} |
100 |
|
|
|
101 |
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
21 |
const std::string hexa_mask = config.get<std::string>(s_QUERY_CONFIG, ""); |
102 |
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 |
if(!hexa_mask.empty()) |
103 |
|
|
{ |
104 |
|
|
SIGHT_ASSERT( |
105 |
|
|
"Hexadecimal values should start with '0x'" |
106 |
|
|
"Given value : " + hexa_mask, |
107 |
|
|
hexa_mask.length() > 2 |
108 |
|
|
&& hexa_mask.substr(0, 2) == "0x" |
109 |
|
7 |
); |
110 |
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 |
m_query_flags = static_cast<std::uint32_t>(std::stoul(hexa_mask, nullptr, 16)); |
111 |
|
|
} |
112 |
|
|
|
113 |
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
14 |
m_enable_alpha = config.get<bool>(s_TF_ALPHA_CONFIG, m_enable_alpha); |
114 |
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
14 |
m_interactive = config.get<bool>(s_INTERACTIVE_CONFIG, m_interactive); |
115 |
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
14 |
m_priority = config.get<int>(s_PRIORITY_CONFIG, m_priority); |
116 |
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
14 |
m_border = config.get<bool>(s_BORDER_CONFIG, m_border); |
117 |
|
|
|
118 |
|
7 |
const std::string transform_id = |
119 |
3/6
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
|
21 |
config.get<std::string>(sight::viz::scene3d::transformable::TRANSFORM_CONFIG, this->get_id() + "_transform"); |
120 |
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
14 |
this->set_transform_id(transform_id); |
121 |
|
7 |
} |
122 |
|
|
|
123 |
|
|
//------------------------------------------------------------------------------ |
124 |
|
|
|
125 |
|
7 |
void negato3d::starting() |
126 |
|
|
{ |
127 |
|
7 |
adaptor::init(); |
128 |
|
|
|
129 |
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
7 |
this->render_service()->make_current(); |
130 |
|
7 |
{ |
131 |
|
|
// 3D source texture instantiation |
132 |
|
7 |
const auto image = m_image.lock(); |
133 |
4/8
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
|
14 |
m_3d_ogre_texture = std::make_shared<sight::viz::scene3d::texture>(image.get_shared()); |
134 |
|
|
|
135 |
|
|
// TF texture initialization |
136 |
|
7 |
const auto tf = m_tf.lock(); |
137 |
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
|
14 |
m_gpu_tf = std::make_unique<sight::viz::scene3d::transfer_function>(tf.get_shared()); |
138 |
|
7 |
} |
139 |
|
|
|
140 |
|
|
// scene node's instantiation |
141 |
|
7 |
Ogre::SceneNode* const root_scene_node = this->get_scene_manager()->getRootSceneNode(); |
142 |
|
7 |
Ogre::SceneNode* const transform_node = this->get_or_create_transform_node(root_scene_node); |
143 |
|
7 |
m_origin_scene_node = transform_node->createChildSceneNode(); |
144 |
|
7 |
m_negato_scene_node = m_origin_scene_node->createChildSceneNode(); |
145 |
|
|
|
146 |
|
|
// Instantiation of the planes |
147 |
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 7 times.
|
28 |
for(auto& plane : m_planes) |
148 |
|
|
{ |
149 |
|
42 |
plane = std::make_shared<sight::viz::scene3d::plane>( |
150 |
|
✗ |
this->get_id(), |
151 |
|
21 |
m_negato_scene_node, |
152 |
|
21 |
this->get_scene_manager(), |
153 |
|
21 |
m_3d_ogre_texture, |
154 |
|
21 |
m_filtering, |
155 |
|
21 |
m_border, |
156 |
|
42 |
false |
157 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 |
); |
158 |
|
|
} |
159 |
|
|
|
160 |
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 |
if(m_auto_reset_camera) |
161 |
|
|
{ |
162 |
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
14 |
this->render_service()->reset_camera_coordinates(m_layer_id); |
163 |
|
|
} |
164 |
|
|
|
165 |
|
7 |
this->new_image(); |
166 |
|
|
|
167 |
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 |
if(m_interactive) |
168 |
|
|
{ |
169 |
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
|
7 |
auto interactor = std::dynamic_pointer_cast<sight::viz::scene3d::interactor::base>(this->get_sptr()); |
170 |
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
7 |
this->layer()->add_interactor(interactor, m_priority); |
171 |
|
|
|
172 |
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
14 |
m_picking_cross = std::make_unique<sight::viz::scene3d::picking_cross>( |
173 |
2/6
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
14 |
this->get_id(), |
174 |
|
7 |
*this->get_scene_manager(), |
175 |
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 |
*m_negato_scene_node |
176 |
|
7 |
); |
177 |
|
7 |
} |
178 |
|
|
|
179 |
|
|
// Set the visibility of the 3D Negato |
180 |
|
7 |
this->set_visible(visible()); |
181 |
|
7 |
} |
182 |
|
|
|
183 |
|
|
//----------------------------------------------------------------------------- |
184 |
|
|
|
185 |
|
7 |
service::connections_t negato3d::auto_connections() const |
186 |
|
|
{ |
187 |
|
7 |
service::connections_t connections = { |
188 |
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 |
{m_image, data::image::MODIFIED_SIG, slots::UPDATE_IMAGE}, |
189 |
|
7 |
{m_image, data::image::BUFFER_MODIFIED_SIG, slots::UPDATE_IMAGE}, |
190 |
|
7 |
{m_tf, data::transfer_function::POINTS_MODIFIED_SIG, slots::UPDATE_TF}, |
191 |
|
7 |
{m_tf, data::transfer_function::WINDOWING_MODIFIED_SIG, slots::UPDATE_TF}, |
192 |
|
7 |
{m_tf, data::transfer_function::MODIFIED_SIG, slots::UPDATE_TF}, |
193 |
|
7 |
{m_image, data::image::SLICE_TYPE_MODIFIED_SIG, slots::SLICE_TYPE}, |
194 |
|
7 |
{m_image, data::image::SLICE_INDEX_MODIFIED_SIG, slots::SLICE_INDEX} |
195 |
2/4
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
56 |
}; |
196 |
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
14 |
return connections + adaptor::auto_connections(); |
197 |
7/16
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 7 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 7 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
|
14 |
} |
198 |
|
|
|
199 |
|
|
//------------------------------------------------------------------------------ |
200 |
|
|
|
201 |
|
✗ |
void negato3d::updating() |
202 |
|
|
{ |
203 |
|
✗ |
if(update_needed(update_flags::IMAGE)) |
204 |
|
|
{ |
205 |
|
✗ |
this->new_image(); |
206 |
|
|
} |
207 |
|
✗ |
else if(update_needed(update_flags::TF)) |
208 |
|
|
{ |
209 |
|
✗ |
this->update_tf(); |
210 |
|
|
} |
211 |
|
|
|
212 |
|
✗ |
this->update_done(); |
213 |
|
✗ |
this->request_render(); |
214 |
|
|
} |
215 |
|
|
|
216 |
|
|
//------------------------------------------------------------------------------ |
217 |
|
|
|
218 |
|
7 |
void negato3d::stopping() |
219 |
|
|
{ |
220 |
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
7 |
this->render_service()->make_current(); |
221 |
|
|
|
222 |
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 |
if(m_interactive) |
223 |
|
|
{ |
224 |
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
|
7 |
auto interactor = std::dynamic_pointer_cast<sight::viz::scene3d::interactor::base>(this->get_sptr()); |
225 |
3/8
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
14 |
this->layer()->remove_interactor(interactor); |
226 |
|
7 |
} |
227 |
|
|
|
228 |
|
7 |
m_picked_plane.reset(); |
229 |
|
28 |
std::ranges::for_each(m_planes, [](auto& _p){_p.reset();}); |
230 |
|
|
|
231 |
|
7 |
auto* const scene_manager = this->get_scene_manager(); |
232 |
|
7 |
m_negato_scene_node->removeAndDestroyAllChildren(); |
233 |
|
7 |
scene_manager->destroySceneNode(m_negato_scene_node); |
234 |
|
7 |
m_negato_scene_node = nullptr; |
235 |
|
|
|
236 |
|
7 |
m_origin_scene_node->removeAndDestroyAllChildren(); |
237 |
|
7 |
scene_manager->destroySceneNode(m_origin_scene_node); |
238 |
|
7 |
m_origin_scene_node = nullptr; |
239 |
|
|
|
240 |
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 |
m_picking_cross.reset(); |
241 |
|
|
|
242 |
|
7 |
m_3d_ogre_texture.reset(); |
243 |
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 |
m_gpu_tf.reset(); |
244 |
|
|
|
245 |
|
7 |
adaptor::deinit(); |
246 |
|
7 |
} |
247 |
|
|
|
248 |
|
|
//------------------------------------------------------------------------------ |
249 |
|
|
|
250 |
|
7 |
void negato3d::new_image() |
251 |
|
|
{ |
252 |
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
7 |
this->render_service()->make_current(); |
253 |
|
|
|
254 |
|
7 |
int axial_idx = 0; |
255 |
|
7 |
int frontal_idx = 0; |
256 |
|
7 |
int sagittal_idx = 0; |
257 |
|
7 |
{ |
258 |
|
7 |
const auto image = m_image.lock(); |
259 |
|
|
|
260 |
4/8
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
|
21 |
if(!data::helper::medical_image::check_image_validity(image.get_shared())) |
261 |
|
|
{ |
262 |
|
✗ |
return; |
263 |
|
|
} |
264 |
|
|
|
265 |
|
|
// Retrieves or creates the slice index fields |
266 |
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 |
m_3d_ogre_texture->update(); |
267 |
|
|
|
268 |
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 |
const auto spacing = sight::viz::scene3d::utils::get_ogre_spacing(*image); |
269 |
|
|
|
270 |
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
7 |
m_origin_scene_node->setPosition(sight::viz::scene3d::utils::get_ogre_origin(*image)); |
271 |
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
7 |
m_origin_scene_node->setOrientation(sight::viz::scene3d::utils::get_ogre_orientation(*image)); |
272 |
|
|
|
273 |
|
|
// Fits the planes to the new texture |
274 |
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 7 times.
|
28 |
for(int orientation_num = 0 ; const auto& plane : m_planes) |
275 |
|
|
{ |
276 |
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 |
plane->update( |
277 |
|
21 |
static_cast<axis_t>(orientation_num++), |
278 |
|
|
spacing, |
279 |
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 |
m_enable_alpha |
280 |
|
|
); |
281 |
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 |
plane->set_query_flags(m_query_flags); |
282 |
|
|
} |
283 |
|
|
|
284 |
|
|
// Update Slice |
285 |
|
7 |
namespace medical_image = data::helper::medical_image; |
286 |
|
|
|
287 |
3/6
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
|
14 |
axial_idx = std::max(0, int(medical_image::get_slice_index(*image, axis_t::axial).value_or(0))); |
288 |
3/6
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
|
14 |
frontal_idx = std::max(0, int(medical_image::get_slice_index(*image, axis_t::frontal).value_or(0))); |
289 |
3/6
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
|
14 |
sagittal_idx = std::max(0, int(medical_image::get_slice_index(*image, axis_t::sagittal).value_or(0))); |
290 |
|
7 |
} |
291 |
|
|
|
292 |
|
7 |
this->change_slice_index(axial_idx, frontal_idx, sagittal_idx); |
293 |
|
|
|
294 |
|
|
// Update transfer function in Gpu programs |
295 |
|
7 |
this->update_tf(); |
296 |
|
|
|
297 |
|
7 |
this->apply_visibility(); |
298 |
|
|
|
299 |
|
7 |
this->request_render(); |
300 |
|
|
} |
301 |
|
|
|
302 |
|
|
//------------------------------------------------------------------------------ |
303 |
|
|
|
304 |
|
15 |
void negato3d::change_slice_type(int /*unused*/, int /*unused*/) |
305 |
|
|
{ |
306 |
1/2
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 |
this->render_service()->make_current(); |
307 |
|
|
|
308 |
|
15 |
this->update_tf(); |
309 |
|
|
|
310 |
|
15 |
this->request_render(); |
311 |
|
15 |
} |
312 |
|
|
|
313 |
|
|
//------------------------------------------------------------------------------ |
314 |
|
|
|
315 |
|
23 |
void negato3d::change_slice_index(int _axial_index, int _frontal_index, int _sagittal_index) |
316 |
|
|
{ |
317 |
|
23 |
const auto image = m_image.lock(); |
318 |
|
|
|
319 |
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 |
auto img_size = image->size(); |
320 |
|
|
|
321 |
|
|
// Sometimes, the image can contain only one slice, |
322 |
|
|
// it results into a division by 0 when the range is transformed between [0-1]. |
323 |
|
|
// So we increase the image size to 2 to divide by 1. |
324 |
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 |
img_size[0] = img_size[0] == 1 ? 2 : img_size[0]; |
325 |
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 |
img_size[1] = img_size[1] == 1 ? 2 : img_size[1]; |
326 |
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 |
img_size[2] = img_size[2] == 1 ? 2 : img_size[2]; |
327 |
|
|
|
328 |
|
23 |
const std::array<float, 3> slice_indices = { |
329 |
|
23 |
static_cast<float>(_sagittal_index) / (static_cast<float>(img_size[0] - 1)), |
330 |
|
23 |
static_cast<float>(_frontal_index) / (static_cast<float>(img_size[1] - 1)), |
331 |
|
23 |
static_cast<float>(_axial_index) / (static_cast<float>(img_size[2] - 1)) |
332 |
|
23 |
}; |
333 |
|
|
|
334 |
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 23 times.
|
92 |
for(std::uint8_t i = 0 ; i < 3 ; ++i) |
335 |
|
|
{ |
336 |
1/2
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
|
69 |
m_planes[i]->change_slice(slice_indices); |
337 |
|
|
} |
338 |
|
|
|
339 |
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 |
this->request_render(); |
340 |
|
23 |
} |
341 |
|
|
|
342 |
|
|
//----------------------------------------------------------------------------- |
343 |
|
|
|
344 |
|
22 |
void negato3d::update_tf() |
345 |
|
|
{ |
346 |
1/2
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
|
22 |
this->render_service()->make_current(); |
347 |
|
22 |
m_gpu_tf->update(); |
348 |
|
|
|
349 |
|
|
// Sends the TF texture to the negato-related passes |
350 |
|
88 |
std::ranges::for_each(m_planes, [this](auto& _p){_p->set_tf_data(*m_gpu_tf.get());}); |
351 |
|
|
|
352 |
|
22 |
this->request_render(); |
353 |
|
22 |
} |
354 |
|
|
|
355 |
|
|
//----------------------------------------------------------------------------- |
356 |
|
|
|
357 |
|
✗ |
void negato3d::set_transparency(double _transparency) |
358 |
|
|
{ |
359 |
|
✗ |
SIGHT_ASSERT("Service not started", this->started()); |
360 |
|
|
|
361 |
|
✗ |
const float opacity = 1.F - static_cast<float>(_transparency); |
362 |
|
✗ |
std::ranges::for_each(m_planes, [opacity](auto& _p){_p->set_entity_opacity(opacity);}); |
363 |
|
|
|
364 |
|
✗ |
this->request_render(); |
365 |
|
|
} |
366 |
|
|
|
367 |
|
|
//------------------------------------------------------------------------------ |
368 |
|
|
|
369 |
|
21 |
void negato3d::set_visible(bool _visible) |
370 |
|
|
{ |
371 |
|
84 |
std::ranges::for_each(m_planes, [_visible](auto& _p){_p->set_visible(_visible);}); |
372 |
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
|
21 |
if(m_auto_reset_camera) |
373 |
|
|
{ |
374 |
1/2
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
|
42 |
this->render_service()->reset_camera_coordinates(m_layer_id); |
375 |
|
|
} |
376 |
|
|
|
377 |
|
21 |
this->request_render(); |
378 |
|
21 |
} |
379 |
|
|
|
380 |
|
|
//------------------------------------------------------------------------------ |
381 |
|
|
|
382 |
|
20 |
void negato3d::set_planes_query_flags(std::uint32_t _flags) |
383 |
|
|
{ |
384 |
|
60 |
std::ranges::for_each(m_planes, [_flags](auto& _p){_p->set_query_flags(_flags);}); |
385 |
|
|
} |
386 |
|
|
|
387 |
|
|
//------------------------------------------------------------------------------ |
388 |
|
|
|
389 |
|
10 |
void negato3d::mouse_move_event(mouse_button _button, modifier /*_mods*/, int _x, int _y, int /*_dx*/, int /*_dy*/) |
390 |
|
|
{ |
391 |
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7 times.
|
10 |
if(m_picked_plane) |
392 |
|
|
{ |
393 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 |
if(_button == mouse_button::middle) |
394 |
|
|
{ |
395 |
|
✗ |
this->move_slices(_x, _y); |
396 |
|
|
} |
397 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 |
else if(_button == mouse_button::right) |
398 |
|
|
{ |
399 |
|
✗ |
const auto dx = static_cast<double>(_x - m_initial_pos[0]); |
400 |
|
✗ |
const auto dy = static_cast<double>(m_initial_pos[1] - _y); |
401 |
|
|
|
402 |
|
✗ |
this->update_windowing(dx, dy); |
403 |
|
|
} |
404 |
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 |
else if(_button == mouse_button::left) |
405 |
|
|
{ |
406 |
|
3 |
this->pick_intensity(_x, _y); |
407 |
|
|
} |
408 |
|
|
|
409 |
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 |
this->layer()->cancel_further_interaction(); |
410 |
|
|
} |
411 |
|
10 |
} |
412 |
|
|
|
413 |
|
|
//------------------------------------------------------------------------------ |
414 |
|
|
|
415 |
|
20 |
void negato3d::button_press_event(mouse_button _button, modifier /*_mods*/, int _x, int _y) |
416 |
|
|
{ |
417 |
|
20 |
m_picked_plane.reset(); |
418 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 |
m_picking_cross->set_visible(false); |
419 |
|
|
|
420 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 |
if(_button == mouse_button::middle) |
421 |
|
|
{ |
422 |
|
✗ |
this->move_slices(_x, _y); |
423 |
|
|
} |
424 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 |
else if(_button == mouse_button::right) |
425 |
|
|
{ |
426 |
|
✗ |
if(this->get_picked_slices(_x, _y) != std::nullopt) |
427 |
|
|
{ |
428 |
|
✗ |
const auto tf = m_tf.const_lock(); |
429 |
|
|
|
430 |
|
✗ |
m_initial_level = tf->level(); |
431 |
|
✗ |
m_initial_window = tf->window(); |
432 |
|
|
|
433 |
|
✗ |
m_initial_pos = {_x, _y}; |
434 |
|
|
} |
435 |
|
|
} |
436 |
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 |
else if(_button == mouse_button::left) |
437 |
|
|
{ |
438 |
|
20 |
this->pick_intensity(_x, _y); |
439 |
|
|
} |
440 |
|
|
|
441 |
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
|
20 |
if(m_picked_plane) |
442 |
|
|
{ |
443 |
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
36 |
this->layer()->cancel_further_interaction(); |
444 |
|
|
} |
445 |
|
20 |
} |
446 |
|
|
|
447 |
|
|
//------------------------------------------------------------------------------ |
448 |
|
|
|
449 |
|
20 |
void negato3d::button_release_event(mouse_button /*_button*/, modifier /*_mods*/, int /*_x*/, int /*_y*/) |
450 |
|
|
{ |
451 |
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
|
20 |
if(m_picked_plane) |
452 |
|
|
{ |
453 |
|
18 |
m_picked_plane->set_render_queuer_group_and_priority(sight::viz::scene3d::rq::SURFACE_ID, 0); |
454 |
|
18 |
m_picked_plane.reset(); |
455 |
|
|
} |
456 |
|
|
|
457 |
|
20 |
m_picking_cross->set_visible(false); |
458 |
3/8
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
40 |
this->signal<signals::picked_voxel_t>(signals::PICKED_VOXEL)->async_emit(""); |
459 |
|
20 |
this->set_planes_query_flags(m_query_flags); // Make all planes pickable again. |
460 |
|
20 |
} |
461 |
|
|
|
462 |
|
|
//------------------------------------------------------------------------------ |
463 |
|
|
|
464 |
|
✗ |
void negato3d::move_slices(int _x, int _y) |
465 |
|
|
{ |
466 |
|
✗ |
const auto pick_res = this->get_picked_slices( |
467 |
|
|
_x, |
468 |
|
|
_y |
469 |
|
|
); |
470 |
|
|
|
471 |
|
✗ |
if(pick_res.has_value()) |
472 |
|
|
{ |
473 |
|
✗ |
const auto image = m_image.lock(); |
474 |
|
|
|
475 |
|
✗ |
auto picked_pt = pick_res.value(); |
476 |
|
|
|
477 |
|
✗ |
std::ranges::for_each( |
478 |
|
✗ |
m_planes, |
479 |
|
✗ |
[this](auto& _p) |
480 |
|
|
{ |
481 |
|
✗ |
if(_p != m_picked_plane) |
482 |
|
|
{ |
483 |
|
✗ |
_p->set_query_flags(0x0); |
484 |
|
|
} |
485 |
|
✗ |
}); |
486 |
|
|
|
487 |
|
✗ |
const auto picked_voxel = geometry::data::world_to_image(*image, picked_pt, true, true); |
488 |
|
|
|
489 |
|
✗ |
image->async_emit( |
490 |
|
|
data::image::SLICE_INDEX_MODIFIED_SIG, |
491 |
|
✗ |
int(picked_voxel[2]), |
492 |
|
✗ |
int(picked_voxel[1]), |
493 |
|
✗ |
int(picked_voxel[0]) |
494 |
|
|
); |
495 |
|
|
} |
496 |
|
|
} |
497 |
|
|
|
498 |
|
|
//------------------------------------------------------------------------------ |
499 |
|
|
|
500 |
|
✗ |
void negato3d::update_slices_from_world(double _x, double _y, double _z) |
501 |
|
|
{ |
502 |
|
✗ |
const auto image = m_image.lock(); |
503 |
|
|
|
504 |
|
✗ |
Ogre::Vector3 point = {static_cast<float>(_x), static_cast<float>(_y), static_cast<float>(_z)}; |
505 |
|
✗ |
Ogre::Vector3i slice_idx; |
506 |
|
✗ |
try |
507 |
|
|
{ |
508 |
|
✗ |
slice_idx = sight::viz::scene3d::utils::world_to_slices(*image, point); |
509 |
|
|
} |
510 |
|
✗ |
catch(core::exception& e) |
511 |
|
|
{ |
512 |
|
✗ |
SIGHT_WARN("Cannot update slice index: " << e.what()); |
513 |
|
✗ |
return; |
514 |
|
|
} |
515 |
|
|
|
516 |
|
✗ |
image->async_emit( |
517 |
|
|
data::image::SLICE_INDEX_MODIFIED_SIG, |
518 |
|
✗ |
int(slice_idx[2]), |
519 |
|
✗ |
int(slice_idx[1]), |
520 |
|
✗ |
int(slice_idx[0]) |
521 |
|
|
); |
522 |
|
|
} |
523 |
|
|
|
524 |
|
|
//------------------------------------------------------------------------------ |
525 |
|
|
|
526 |
|
23 |
void negato3d::pick_intensity(int _x, int _y) |
527 |
|
|
{ |
528 |
|
23 |
auto sig = this->signal<signals::picked_voxel_t>(signals::PICKED_VOXEL); |
529 |
2/4
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
✗ Branch 4 not taken.
|
23 |
if(sig->num_connections() > 0) |
530 |
|
|
{ |
531 |
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 |
const auto picked_pos = this->get_picked_slices(_x, _y); |
532 |
|
|
|
533 |
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2 times.
|
23 |
if(picked_pos.has_value()) |
534 |
|
|
{ |
535 |
|
21 |
const auto image = m_image.lock(); |
536 |
|
|
|
537 |
4/8
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 21 times.
|
63 |
if(!data::helper::medical_image::check_image_validity(image.get_shared())) |
538 |
|
|
{ |
539 |
|
✗ |
return; |
540 |
|
|
} |
541 |
|
|
|
542 |
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 |
const auto cross_lines = m_picked_plane->compute_cross(*picked_pos, *image); |
543 |
|
|
|
544 |
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 |
m_picking_cross->update(cross_lines[0], cross_lines[1], cross_lines[2], cross_lines[3]); |
545 |
|
|
|
546 |
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 |
const auto picking_text = sight::viz::scene3d::utils::pick_image(*image, *picked_pos); |
547 |
2/4
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
|
21 |
sig->async_emit(picking_text); |
548 |
|
|
|
549 |
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 |
this->request_render(); |
550 |
|
|
|
551 |
|
|
// Render the picked plane before the widget. |
552 |
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 |
m_picked_plane->set_render_queuer_group_and_priority(sight::viz::scene3d::rq::NEGATO_WIDGET_ID, 0); |
553 |
|
21 |
} |
554 |
|
|
} |
555 |
|
23 |
} |
556 |
|
|
|
557 |
|
|
//------------------------------------------------------------------------------ |
558 |
|
|
|
559 |
|
23 |
std::optional<Ogre::Vector3> negato3d::get_picked_slices(int _x, int _y) |
560 |
|
|
{ |
561 |
|
23 |
Ogre::SceneManager* sm = this->get_scene_manager(); |
562 |
|
23 |
const auto result = sight::viz::scene3d::utils::pick_object(_x, _y, m_query_flags, *sm); |
563 |
|
|
|
564 |
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2 times.
|
23 |
if(result.has_value()) |
565 |
|
|
{ |
566 |
2/2
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 21 times.
|
63 |
const auto is_picked = [&result](const auto& _p){return _p->get_movable_object() == result->first;}; |
567 |
|
21 |
const auto it = std::ranges::find_if(m_planes, is_picked); // NOLINT(readability-qualified-auto,llvm-qualified-auto) |
568 |
|
|
|
569 |
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
|
21 |
if(it != m_planes.cend()) |
570 |
|
|
{ |
571 |
|
21 |
m_picked_plane = *it; |
572 |
|
21 |
return result->second; |
573 |
|
|
} |
574 |
|
|
} |
575 |
|
|
|
576 |
|
2 |
return std::nullopt; |
577 |
|
|
} |
578 |
|
|
|
579 |
|
|
//------------------------------------------------------------------------------ |
580 |
|
|
|
581 |
|
✗ |
void negato3d::update_windowing(double _dw, double _dl) |
582 |
|
|
{ |
583 |
|
✗ |
const double new_window = m_initial_window + _dw; |
584 |
|
✗ |
const double new_level = m_initial_level - _dl; |
585 |
|
|
|
586 |
|
|
{ |
587 |
|
✗ |
const auto tf = m_tf.lock(); |
588 |
|
|
|
589 |
|
✗ |
tf->set_window(new_window); |
590 |
|
✗ |
tf->set_level(new_level); |
591 |
|
✗ |
const auto sig = tf->signal<data::transfer_function::windowing_modified_signal_t>( |
592 |
|
|
data::transfer_function::WINDOWING_MODIFIED_SIG |
593 |
|
✗ |
); |
594 |
|
|
{ |
595 |
|
✗ |
sig->async_emit(new_window, new_level); |
596 |
|
|
} |
597 |
|
|
} |
598 |
|
|
} |
599 |
|
|
|
600 |
|
|
} // namespace sight::module::viz::scene3d::adaptor. |
601 |
|
|
|