GCC Code Coverage Report


./
File: modules/viz/scene2d/adaptor/transfer_function.hpp
Date: 2025-01-21 16:21:04
Lines:
2/2
100.0%
Functions:
3/5
60.0%
Branches:
4/9
44.4%

Line Branch Exec Source
1 /************************************************************************
2 *
3 * Copyright (C) 2020-2024 IRCAD France
4 * Copyright (C) 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 #pragma once
24
25 #include <data/transfer_function.hpp>
26
27 #include <viz/scene2d/adaptor.hpp>
28
29 #include <QGraphicsItemGroup>
30
31 namespace sight::module::viz::scene2d::adaptor
32 {
33
34 /**
35 * @brief Defines an adaptor to display a map of TF and interact with them.
36 *
37 * The following actions are available:
38 * - Left mouse click: selects a new current TF or move the current clicked TF point.
39 * - Left mouse double click: adds a new TF point to the current TF or open a color dialog
40 * to change the current clicked TF point.
41 * - Middle mouse click: adjusts the transfer function level and window by moving
42 * the mouse up/down and left/right respectively.
43 * - Right mouse click: remove the current clicked TF point or open a context menu
44 * to manage multiple actions which are 'delete', 'add ramp', 'clamp' or 'linear'.
45 *
46 * @section XML XML Configuration
47 *
48 * @code{.xml}
49 <service uid="..." type="sight::module::viz::scene2d::adaptor::transfer_function" >
50 <in key="viewport" uid="..." />
51 <inout key="tf" uid="..." />
52 <config lineColor="lightGray" pointColor="lightGray" xAxis="xAxis" yAxis="yAxis" zValue="0" />
53 </service>
54 @endcode
55 *
56 * @subsection Input Input
57 * - \b viewport [sight::viz::scene2d::data::viewport]: object listened to update the adaptor.
58 * - \b tf [sight::data::transfer_function](optional): current transfer function used to change editor selection.
59 * It should be the same TF as the output.
60 *
61 * @subsection Configuration Configuration
62 * - \b config (mandatory): contains the adaptor configuration.
63 * - \b xAxis (optional): x axis associated to the adaptor.
64 * - \b yAxis (optional): y axis associated to the adaptor.
65 * - \b zValue (optional, default="0"): z value of the layer.
66 * - \b lineColor (optional, default="#FFFFFF"): color of the lines between the points.
67 * - \b pointColor (optional, default="#FFFFFF"): outline color of circles representing the TF points.
68 * - \b secondOpacity (optional, default="0.0"): opacity of TF that not the current one.
69 * - \b pointSize (optional, default="0.03"): size of TF points in a ratio relative to the window.
70 * - \b opacity (optional, default="1.0"): opacity of the gradient.
71 * - \b interactive (optional, true/false, default="false"): enables interactions.
72 */
73 class transfer_function : public QObject,
74 public sight::viz::scene2d::adaptor
75 {
76 Q_OBJECT
77
78 public:
79
80
4/9
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 937 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
2832 SIGHT_DECLARE_SERVICE(transfer_function, sight::viz::scene2d::adaptor);
81
82 /// Creates the adaptor.
83 transfer_function() noexcept;
84
85 /// Destroys the adaptor.
86 ~transfer_function() noexcept override;
87
88 protected:
89
90 /// Configures the adaptor.
91 void configuring() override;
92
93 /**
94 * @brief Initializes the current TF, the layer and draw all TF.
95 *
96 * @see updating()
97 */
98 void starting() override;
99
100 /**
101 * @brief Proposals to connect service slots to associated object signals.
102 * @return A map of each proposed connection.
103 *
104 * Connect sight::viz::scene2d::data::viewport::MODIFIED_SIG of s_VIEWPORT_INPUT to
105 * module::viz::scene2d::adaptor::transfer_function::service::slots::UPDATE.
106 * Connect data::object::MODIFIED_SIG of s_TF_POOL_INOUT to
107 * module::viz::scene2d::adaptor::transfer_function::service::slots::UPDATE.
108 * Connect data::map::ADDED_OBJECTS_SIGof s_TF_POOL_INOUT to
109 * module::viz::scene2d::adaptor::transfer_function::service::slots::UPDATE.
110 * Connect data::map::REMOVED_OBJECTS_SIG of s_TF_POOL_INOUT to
111 * module::viz::scene2d::adaptor::transfer_function::service::slots::UPDATE.
112 */
113 connections_t auto_connections() const override;
114
115 /// Release all graphics items and draw all TF, all TF connections a established here.
116 void updating() override;
117
118 /// Release all graphic items and disconect all TF in the map.
119 void stopping() override;
120
121 private:
122
123 using vec2d_t = sight::viz::scene2d::vec2d_t;
124
125 /// Represents a sub-TF which is a TF of the input map.
126 24 struct piece_view
127 {
128 /// Contains the TF data.
129 data::transfer_function_piece::sptr m_tf;
130
131 /// Sets the z value in the local layer.
132 int m_z_index {0};
133
134 /// Contains a set of graphic point and its coordinates in the window/level space.
135 std::vector<std::pair<vec2d_t, QGraphicsEllipseItem*> > m_tf_points;
136
137 /// Contains the graphic gradient.
138 std::vector<QAbstractGraphicsShapeItem*> m_tf_polygons;
139 };
140
141 /// Deletes piece views in @ref m_pieceView and clears them.
142 void release_tf_data();
143
144 /**
145 * @brief Creates pieceView for each TF in the map, fills basic data and create graphic points.
146 *
147 * @see createPieceView(const data::transfer_function::sptr _tf, int _zIndex)
148 */
149 void create_tf_points();
150
151 /// Removes all graphic points in @ref m_pieceView from the layer and deletes them.
152 void destroy_tf_points();
153
154 /// Creates a piece view from a TF, fills basic data and creates graphic points.
155 piece_view* create_piece_view(const data::transfer_function_piece::sptr _tf, int _z_index);
156
157 /// Creates the gradient of each piece view and stores it in each element of @ref m_pieceView.
158 void create_tf_polygons();
159
160 /**
161 * @brief Creates lines and gradient polygons of a pieceView.
162 * @param _piece_view the pieceView used to create the gradient and store the generated graphic item.
163 */
164 void create_tf_polygon(piece_view* _piece_view);
165
166 /**
167 * @brief Removes all graphic gradient in @ref m_pieceView from the layer and deletes them.
168 *
169 * @see destroyTFPolygons()
170 */
171 void destroy_tf_polygons();
172
173 /**
174 * @brief Removes graphic gradient of the pieceView from the layer and deletes them.
175 * @param _piece_view to where destory the polygon.
176 */
177 void destroy_tf_polygon(piece_view* _piece_view);
178
179 /**
180 * @brief Creates lines and linear gradient polygons of a pieceView.
181 * @param _piece_view the pieceView used to create the gradient.
182 * @param _position the position vector to fill.
183 * @param _grad the gradient to create.
184 * @param _distance_max the maximum distance used by the gradient.
185 */
186 static void build_linear_polygons(
187 piece_view* _piece_view,
188 QVector<QPointF>& _position,
189 QLinearGradient& _grad,
190 double _distance_max
191 );
192
193 /**
194 * @brief Creates lines and nearest gradient polygons of a pieceView.
195 * @param _piece_view the pieceView used to create the gradient.
196 * @param _position the position vector to fill.
197 * @param _grad the gradient to create.
198 * @param _distance_max the maximum distance used by the gradient.
199 */
200 static void build_nearest_polygons(
201 piece_view* _piece_view,
202 QVector<QPointF>& _position,
203 QLinearGradient& _grad,
204 double _distance_max
205 );
206
207 /// Adds graphic items of @ref m_pieceView to @ref m_layer at the right z-index.
208 void build_layer();
209
210 /**
211 * @brief Changes @ref m_currentTF with the new one.
212 *
213 * Sets the new current TF as output of this adaptor and updates z-index of each pieceView in @ref m_pieceView.
214 *
215 * @param _piece_view the new current pieceView.
216 */
217 void set_current_tf(piece_view* _piece_view);
218
219 /**
220 * @brief Get pieceView that match the clicked coord of the event.
221 * @param _event the 2D scene event.
222 * @return A list of pieceView.
223 */
224 std::vector<piece_view*> get_matching_piece_view(const sight::viz::scene2d::data::event& _event) const;
225
226 /**
227 * @brief Filters the event to call the right methods from mouse informations.
228 * @param _event the 2D scene event.
229 *
230 * The following actions are available:
231 * - Left mouse click: selects a new current TF or move the current clicked TF point.
232 * - Left mouse double click: adds a new TF point to the current TF or open a color dialog
233 * to change the current clicked TF point.
234 * - Middle mouse click: adjusts the transfer function level and window by moving
235 * the mouse up/down and left/right respectively.
236 * - Right mouse click: remove the current clicked TF point or open a context menu
237 * to manage multiple actions which are 'delete', 'add ramp', 'clamp' or 'linear'.
238 * - Wheel move: updates the whole current TF opacity.
239 */
240 void process_interaction(sight::viz::scene2d::data::event& _event) override;
241
242 /**
243 * @brief Finds the nearest pieceView and set it a the current one.
244 * @param _event the 2D scene event.
245 *
246 * @see setCurrentTF(PieceView* const)
247 */
248 void left_button_click_event(const sight::viz::scene2d::data::event& _event);
249
250 /**
251 * @brief Sets @ref m_capturedTFPoint and highlight the captured clicked point.
252 * @param _piece_view the selected pieceView.
253 * @param _tf_point the selected TF point.
254 */
255 void left_button_click_on_point_event(
256 piece_view* _piece_view,
257 std::pair<vec2d_t,
258 QGraphicsEllipseItem*>& _tf_point
259 );
260
261 /**
262 * @brief Move @ref m_capturedTFPoint to the new mouse position and update the related TF.
263 * @param _event the 2D scene event.
264 *
265 * @pre m_capturedTFPoint must be previously sets.
266 * @see leftButtonClickOnPointEvent(PieceView* const, std::pair< vec2d_t, QGraphicsEllipseItem* >&)
267 */
268 void mouse_move_on_point_event(piece_view* _piece_view, const sight::viz::scene2d::data::event& _event);
269
270 /**
271 * @brief Resets the captured TF point highlighting and sets @ref m_capturedTFPoint to null.
272 *
273 * @pre m_capturedTFPoint must be previously sets.
274 * @see leftButtonClickOnPointEvent(PieceView* const, std::pair< vec2d_t, QGraphicsEllipseItem* >&)
275 */
276 void left_button_release_event();
277
278 /**
279 * @brief Removes a TF point from the current pieceView and update the related TF.
280 * @param _piece_view the selected pieceView.
281 * @param _tf_point the selected TF point.
282 */
283 void right_button_click_on_point_event(
284 piece_view* _piece_view,
285 std::pair<vec2d_t, QGraphicsEllipseItem*>& _tf_point
286 );
287
288 /**
289 * @brief Changes the TF point color by opening a color dialog and update the related TF.
290 * @param _piece_view the selected pieceView.
291 * @param _tf_point the selected TF point.
292 */
293 void left_button_double_click_on_point_event(
294 piece_view* _piece_view,
295 std::pair<vec2d_t, QGraphicsEllipseItem*>& _tf_point
296 );
297
298 /**
299 * @brief Adds a new TF point to the current pieceView and update the related TF.
300 * @param _event the 2D scene event.
301 */
302 void left_button_double_click_event(const sight::viz::scene2d::data::event& _event);
303
304 /**
305 * @brief Sets @ref m_capturedTF if the clicked coord if over the current TF.
306 * @param _event the 2D scene event.
307 */
308 void mid_button_click_event(sight::viz::scene2d::data::event& _event);
309
310 /**
311 * @brief Update the window/level of the current TF relatively to the mouse movement.
312 * @param _event the 2D scene event.
313 *
314 * @pre m_capturedTF must be previously sets.
315 * @see midButtonClickEvent(const sight::viz::scene2d::data::Event&)
316 */
317 void mouse_move_on_piece_view_event(const sight::viz::scene2d::data::event& _event);
318
319 /**
320 * @brief Resets @ref m_capturedTF.
321 *
322 * @pre m_capturedTF must be previously sets.
323 * @see midButtonClickEvent(const sight::viz::scene2d::data::Event&)
324 */
325 void mid_button_release_event();
326
327 /**
328 * @brief Open a context menu to delete or create TF.
329 * @param _event the 2D scene event.
330 */
331 void right_button_c_lick_event(const sight::viz::scene2d::data::event& _event);
332
333 /**
334 * @brief Updates the whole current TF opacity.
335 * @param _event the 2D scene event.
336 */
337 void mid_button_wheel_move_event(sight::viz::scene2d::data::event& _event);
338
339 /// Deletes the current TF and change the current TF.
340 void remove_current_tf();
341
342 /**
343 * @brief Sets if the current TF is clamped or not.
344 * @param _clamp the clamp status.
345 */
346 void clamp_current_tf(bool _clamp);
347
348 /**
349 * @brief Sets if the current TF interpolation mode is linear or nearest.
350 * @param _linear uses true is the interpolation mode must be linear.
351 */
352 void toggle_linear_current_tf(bool _linear);
353
354 /**
355 * @brief Adds a new TF to the map and re draw the scene.
356 * @param _tf the new TF to add.
357 */
358 void add_new_tf(const data::transfer_function_piece::sptr _tf);
359
360 /**
361 * @brief Adds a left ramp pieceView and update the map.
362 * @param _event the 2D scene event.
363 *
364 * @see addNewTF(const data::transfer_function::sptr, const data::map::key_t&)
365 */
366 void add_left_ramp(const sight::viz::scene2d::data::event& _event);
367
368 /**
369 * @brief Adds a right ramp pieceView and update the map.
370 * @param _event the 2D scene event.
371 *
372 * @see addNewTF(const data::transfer_function::sptr, const data::map::key_t&)
373 */
374 void add_right_ramp(const sight::viz::scene2d::data::event& _event);
375
376 /**
377 * @brief Adds a trapeze pieceView and update the map.
378 * @param _event the 2D scene event.
379 *
380 * @see addNewTF(const data::transfer_function::sptr, const data::map::key_t&)
381 */
382 void add_trapeze(const sight::viz::scene2d::data::event& _event);
383
384 /// Updates the transfer function.
385 void update_tf();
386
387 /// Defines the size of TF points in a ratio relative to the window.
388 float m_point_size {0.03F};
389
390 /// Defines the pen used by gradients.
391 QPen m_polygons_pen;
392
393 /// Defines the pen used by TF points.
394 QPen m_points_pen;
395
396 /// Defines the opacity used for TF except for the current one.
397 float m_second_opacity {0.0F};
398
399 /// Sets if interactions are enable or not.
400 bool m_interactive {true};
401
402 /// Stores all created piece view.
403 std::vector<piece_view*> m_piece_view;
404
405 /// Stores the main layer.
406 QGraphicsItemGroup* m_layer {};
407
408 /**
409 * We never know if a single click might be followed by another single click effectively resulting in a double
410 * click. Qt does it and delivers events for double clicks (QEvent.MouseButtonDblClick). On the other hand Qt still
411 * delivers events for single clicks (QEvent.MouseButtonPress) even in the case of a double click, but only one.
412 * We must differentiate them correctly. We do it with an additional timer that needs to be a bit longer than the
413 * inbuilt Qt timer for detecting double clicks.
414 */
415 QTimer* m_event_filter {nullptr};
416
417 /// Stores the current working TF.
418 data::transfer_function_piece::sptr m_current_tf {nullptr};
419
420 /// Stores the captured clicked point.
421 std::pair<vec2d_t, QGraphicsEllipseItem*>* m_captured_tf_point {nullptr};
422
423 /// Stores the captured clicked TF and the current mouse position,
424 /// the first coord is in the window/level space and the second in screen space,
425 /// it allows to adjust the window/level of the current TF.
426 std::pair<data::transfer_function_piece::sptr, sight::viz::scene2d::vec2d_t> m_captured_tf;
427
428 static constexpr std::string_view VIEWPORT_INPUT = "viewport";
429 static constexpr std::string_view CURRENT_TF_INOUT = "tf";
430
431 data::ptr<sight::viz::scene2d::data::viewport, sight::data::access::in> m_viewport {this, VIEWPORT_INPUT};
432 data::ptr<sight::data::transfer_function, sight::data::access::inout> m_tf {this, CURRENT_TF_INOUT};
433 };
434
435 } // namespace sight::module::viz::scene2d::adaptor
436