GCC Code Coverage Report


./
File: libs/viz/scene3d/vr/volume_renderer.cpp
Date: 2025-01-21 16:21:04
Lines:
74/81
91.4%
Functions:
8/9
88.9%
Branches:
20/50
40.0%

Line Branch Exec Source
1 /************************************************************************
2 *
3 * Copyright (C) 2016-2024 IRCAD France
4 * Copyright (C) 2016-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 NOLINT
24
25 #include "viz/scene3d/vr/volume_renderer.hpp"
26
27 #include "viz/scene3d/layer.hpp"
28
29 #include <boost/algorithm/clamp.hpp>
30
31 #include <utility>
32
33 namespace sight::viz::scene3d::vr
34 {
35
36 const std::array<Ogre::Vector3, 8> volume_renderer::IMAGE_POSITIONS =
37 {
38 Ogre::Vector3(1, 1, 1),
39 Ogre::Vector3(1, 0, 1),
40 Ogre::Vector3(1, 1, 0),
41 Ogre::Vector3(0, 1, 1),
42 Ogre::Vector3(0, 0, 1),
43 Ogre::Vector3(1, 0, 0),
44 Ogre::Vector3(0, 1, 0),
45 Ogre::Vector3(0, 0, 0)
46 };
47
48 //-----------------------------------------------------------------------------
49
50 7 volume_renderer::volume_renderer(
51 std::string _parent_id,
52 Ogre::SceneManager* const _scene_manager,
53 Ogre::SceneNode* const _volume_node,
54 sight::data::image::csptr _image,
55 sight::data::image::csptr _mask,
56 sight::data::transfer_function::csptr _tf,
57 std::uint16_t _samples,
58 bool _with_buffer,
59 bool _preintegration
60 7 ) :
61 m_parent_id(std::move(_parent_id)),
62
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 m_scene_manager(_scene_manager),
63
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 m_3d_ogre_texture(std::make_shared<sight::viz::scene3d::texture>(_image)),
64
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 m_mask_texture(std::make_shared<sight::viz::scene3d::texture>(_mask)),
65 7 m_gpu_volume_tf(std::make_shared<sight::viz::scene3d::transfer_function>(_tf)),
66
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 m_with_buffer(_with_buffer),
67 7 m_preintegration(_preintegration),
68 7 m_volume_scene_node(_volume_node),
69
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 m_camera(m_scene_manager->getCamera(viz::scene3d::layer::DEFAULT_CAMERA_NAME)),
70 7 m_nb_slices(_samples),
71
2/4
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
21 m_clipped_image_positions(IMAGE_POSITIONS)
72 {
73 //Transfer function and preintegration table
74 7 {
75
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 m_pre_integration_table.create_texture(m_parent_id);
76 }
77
78 // 3D source texture instantiation
79
80
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if(m_with_buffer)
81 {
82 // 3D source texture instantiation
83 m_buffering_texture = std::make_shared<sight::viz::scene3d::texture>(_image, "_buffered");
84 }
85
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
7 }
86
87 //-----------------------------------------------------------------------------
88
89 28 volume_renderer::~volume_renderer()
90 {
91 14 m_mask_texture.reset();
92 14 m_3d_ogre_texture.reset();
93
94
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
14 if(m_buffering_texture)
95 {
96 m_buffering_texture.reset();
97 }
98
99 14 m_pre_integration_table.remove_texture();
100
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
28 }
101
102 //------------------------------------------------------------------------------
103
104 7 void volume_renderer::load_image()
105 {
106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if(m_with_buffer)
107 {
108 m_buffering_texture->update();
109
110 // Swap texture pointers.
111 {
112 std::lock_guard<std::mutex> swap_lock(m_buffer_swap_mutex);
113 std::swap(m_3d_ogre_texture, m_buffering_texture);
114 }
115 }
116 else
117 {
118 7 m_3d_ogre_texture->update();
119 }
120 7 }
121
122 //------------------------------------------------------------------------------
123
124 7 void volume_renderer::load_mask()
125 {
126 7 m_mask_texture->update();
127 7 }
128
129 //-----------------------------------------------------------------------------
130
131 7 void volume_renderer::clip_image(const Ogre::AxisAlignedBox& _clipping_box)
132 {
133 7 const Ogre::Vector3 min = _clipping_box.getMinimum();
134 7 const Ogre::Vector3 max = _clipping_box.getMaximum();
135
136
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 7 times.
63 for(unsigned i = 0 ; i < 8 ; ++i)
137 {
138 224 m_clipped_image_positions[i] = Ogre::Vector3(
139 56 boost::algorithm::clamp(IMAGE_POSITIONS[i].x, min.x, max.x),
140
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 boost::algorithm::clamp(IMAGE_POSITIONS[i].y, min.y, max.y),
141
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
112 boost::algorithm::clamp(IMAGE_POSITIONS[i].z, min.z, max.z)
142 );
143 }
144 7 }
145
146 //-----------------------------------------------------------------------------
147
148 void volume_renderer::resize_viewport(int /*w*/, int /*h*/)
149 {
150 }
151
152 //-----------------------------------------------------------------------------
153
154 7 void volume_renderer::scale_translate_cube(const data::image& _image)
155 {
156 // Scale the volume based on the image's spacing and move it to the image origin.
157 7 m_volume_scene_node->resetToInitialState();
158
159 7 const auto& spacing = _image.spacing();
160 7 const double width = static_cast<double>(m_3d_ogre_texture->width()) * spacing[0];
161 7 const double height = static_cast<double>(m_3d_ogre_texture->height()) * spacing[1];
162 7 const double depth = static_cast<double>(m_3d_ogre_texture->depth()) * spacing[2];
163
164 7 const Ogre::Vector3 scale_factors(
165 static_cast<Ogre::Real>(width),
166 static_cast<Ogre::Real>(height),
167 static_cast<Ogre::Real>(depth)
168 7 );
169
170 7 m_volume_scene_node->setScale(scale_factors);
171 7 m_volume_scene_node->setPosition(utils::get_ogre_origin(_image));
172 7 m_volume_scene_node->setOrientation(utils::get_ogre_orientation(_image));
173 7 }
174
175 //-----------------------------------------------------------------------------
176
177 7 void volume_renderer::update_sample_distance()
178 {
179 //Update the plane with the current position and direction
180 14 m_camera_info.plane = Ogre::Plane(
181 14 m_volume_scene_node->convertWorldToLocalDirection(m_camera->getRealDirection(), true).normalisedCopy(),
182 7 m_volume_scene_node->convertWorldToLocalPosition(m_camera->getRealPosition())
183 );
184
185 //Compares the distances to the camera plane to get the cube's closest and furthest vertex to the camera
186 105 const auto comp = [this](const Ogre::Vector3& _v1, const Ogre::Vector3& _v2)
187 105 {return m_camera_info.plane.getDistance(_v1) < m_camera_info.plane.getDistance(_v2);};
188
189 //Closest vertex
190 7 {
191 7 const auto iterator = std::min_element( // NOLINT(readability-qualified-auto,llvm-qualified-auto)
192 m_clipped_image_positions.begin(),
193 m_clipped_image_positions.end(),
194 comp
195 );
196 7 const auto index = static_cast<std::size_t>(std::distance(m_clipped_image_positions.begin(), iterator));
197 7 m_camera_info.closest = *iterator;
198 7 m_camera_info.closest_index = index;
199 }
200
201 //Furthest vertex
202 7 {
203 7 const auto iterator = std::max_element( // NOLINT(readability-qualified-auto,llvm-qualified-auto)
204 m_clipped_image_positions.begin(),
205 m_clipped_image_positions.end(),
206 comp
207 );
208 7 const auto index = static_cast<std::size_t>(std::distance(m_clipped_image_positions.begin(), iterator));
209
210 7 m_camera_info.furthest = *iterator;
211 7 m_camera_info.furthest_index = index;
212 }
213
214 //The total distance between the vertices
215 7 const float total_distance =
216 7 std::abs(
217 7 m_camera_info.plane.getDistance(m_camera_info.closest)
218 7 - m_camera_info.plane.getDistance(m_camera_info.furthest)
219 );
220
221 //Then simply uniformly divide it according to the total number of slices
222 7 m_sample_distance = total_distance / static_cast<float>(m_nb_slices);
223
224 //Validation
225 7 SIGHT_ASSERT("Sampled distance is NaN.", !std::isnan(m_sample_distance)); //NaN
226 7 SIGHT_ASSERT("Sample distance is denormalized.", m_sample_distance > std::numeric_limits<float>::min());
227 7 }
228
229 //-----------------------------------------------------------------------------
230
231 } // namespace sight::viz::scene3d::vr
232