comparison Applications/Samples/SingleVolumeApplication.h @ 104:eccd64f8e297 wasm

VolumeImageInteractor
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 01 Jun 2017 10:33:49 +0200
parents 474d85e76499
children e0ddd8cad909
comparison
equal deleted inserted replaced
103:474d85e76499 104:eccd64f8e297
34 namespace OrthancStone 34 namespace OrthancStone
35 { 35 {
36 namespace Samples 36 namespace Samples
37 { 37 {
38 class SingleVolumeApplication : 38 class SingleVolumeApplication :
39 public SampleApplicationBase, 39 public SampleApplicationBase
40 private ILayerSource::IObserver
41 { 40 {
42 private:
43 class Interactor : public IWorldSceneInteractor
44 {
45 private:
46 SingleVolumeApplication& application_;
47
48 public:
49 Interactor(SingleVolumeApplication& application) :
50 application_(application)
51 {
52 }
53
54 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
55 const ViewportGeometry& view,
56 MouseButton button,
57 double x,
58 double y,
59 IStatusBar* statusBar)
60 {
61 return NULL;
62 }
63
64 virtual void MouseOver(CairoContext& context,
65 WorldSceneWidget& widget,
66 const ViewportGeometry& view,
67 double x,
68 double y,
69 IStatusBar* statusBar)
70 {
71 if (statusBar != NULL)
72 {
73 Vector p = dynamic_cast<LayerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
74
75 char buf[64];
76 sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)",
77 p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
78 statusBar->SetMessage(buf);
79 }
80 }
81
82 virtual void MouseWheel(WorldSceneWidget& widget,
83 MouseWheelDirection direction,
84 KeyboardModifiers modifiers,
85 IStatusBar* statusBar)
86 {
87 int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1);
88
89 switch (direction)
90 {
91 case MouseWheelDirection_Up:
92 application_.OffsetSlice(-scale);
93 break;
94
95 case MouseWheelDirection_Down:
96 application_.OffsetSlice(scale);
97 break;
98
99 default:
100 break;
101 }
102 }
103
104 virtual void KeyPressed(WorldSceneWidget& widget,
105 char key,
106 KeyboardModifiers modifiers,
107 IStatusBar* statusBar)
108 {
109 switch (key)
110 {
111 case 's':
112 widget.SetDefaultView();
113 break;
114
115 default:
116 break;
117 }
118 }
119 };
120
121
122 LayerWidget* widget_;
123 const OrthancVolumeImage* volume_;
124 VolumeProjection projection_;
125 std::auto_ptr<VolumeImageGeometry> slices_;
126 size_t slice_;
127
128 void OffsetSlice(int offset)
129 {
130 if (slices_.get() != NULL)
131 {
132 int slice = static_cast<int>(slice_) + offset;
133
134 if (slice < 0)
135 {
136 slice = 0;
137 }
138
139 if (slice >= static_cast<int>(slices_->GetSliceCount()))
140 {
141 slice = slices_->GetSliceCount() - 1;
142 }
143
144 if (slice != static_cast<int>(slice_))
145 {
146 SetSlice(slice);
147 }
148 }
149 }
150
151 void SetSlice(size_t slice)
152 {
153 if (slices_.get() != NULL)
154 {
155 slice_ = slice;
156 widget_->SetSlice(slices_->GetSlice(slice_).GetGeometry());
157 }
158 }
159
160 virtual void NotifyGeometryReady(const ILayerSource& source)
161 {
162 if (slices_.get() == NULL)
163 {
164 slices_.reset(new VolumeImageGeometry(*volume_, projection_));
165 SetSlice(slices_->GetSliceCount() / 2);
166
167 widget_->SetDefaultView();
168 }
169 }
170
171 virtual void NotifyGeometryError(const ILayerSource& source)
172 {
173 }
174
175 virtual void NotifyContentChange(const ILayerSource& source)
176 {
177 }
178
179 virtual void NotifySliceChange(const ILayerSource& source,
180 const Slice& slice)
181 {
182 }
183
184 virtual void NotifyLayerReady(std::auto_ptr<ILayerRenderer>& layer,
185 const ILayerSource& source,
186 const Slice& slice,
187 bool isError)
188 {
189 }
190
191 #if 0
192 class Interactor : public SampleInteractor
193 {
194 private:
195 enum MouseMode
196 {
197 MouseMode_None,
198 MouseMode_TrackCoordinates,
199 MouseMode_LineMeasure,
200 MouseMode_CircleMeasure
201 };
202
203 MouseMode mouseMode_;
204
205 void SetMouseMode(MouseMode mode,
206 IStatusBar* statusBar)
207 {
208 if (mouseMode_ == mode)
209 {
210 mouseMode_ = MouseMode_None;
211 }
212 else
213 {
214 mouseMode_ = mode;
215 }
216
217 if (statusBar)
218 {
219 switch (mouseMode_)
220 {
221 case MouseMode_None:
222 statusBar->SetMessage("Disabling the mouse tools");
223 break;
224
225 case MouseMode_TrackCoordinates:
226 statusBar->SetMessage("Tracking the mouse coordinates");
227 break;
228
229 case MouseMode_LineMeasure:
230 statusBar->SetMessage("Mouse clicks will now measure the distances");
231 break;
232
233 case MouseMode_CircleMeasure:
234 statusBar->SetMessage("Mouse clicks will now draw circles");
235 break;
236
237 default:
238 break;
239 }
240 }
241 }
242
243 public:
244 Interactor(VolumeImage& volume,
245 VolumeProjection projection,
246 bool reverse) :
247 SampleInteractor(volume, projection, reverse),
248 mouseMode_(MouseMode_None)
249 {
250 }
251
252 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
253 const SliceGeometry& slice,
254 const ViewportGeometry& view,
255 MouseButton button,
256 double x,
257 double y,
258 IStatusBar* statusBar)
259 {
260 if (button == MouseButton_Left)
261 {
262 switch (mouseMode_)
263 {
264 case MouseMode_LineMeasure:
265 return new LineMeasureTracker(NULL, slice, x, y, 255, 0, 0, 14 /* font size */);
266
267 case MouseMode_CircleMeasure:
268 return new CircleMeasureTracker(NULL, slice, x, y, 255, 0, 0, 14 /* font size */);
269
270 default:
271 break;
272 }
273 }
274
275 return NULL;
276 }
277
278 virtual void MouseOver(CairoContext& context,
279 WorldSceneWidget& widget,
280 const SliceGeometry& slice,
281 const ViewportGeometry& view,
282 double x,
283 double y,
284 IStatusBar* statusBar)
285 {
286 if (mouseMode_ == MouseMode_TrackCoordinates &&
287 statusBar != NULL)
288 {
289 Vector p = slice.MapSliceToWorldCoordinates(x, y);
290
291 char buf[64];
292 sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)", p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
293 statusBar->SetMessage(buf);
294 }
295 }
296
297
298 virtual void KeyPressed(WorldSceneWidget& widget,
299 char key,
300 KeyboardModifiers modifiers,
301 IStatusBar* statusBar)
302 {
303 switch (key)
304 {
305 case 't':
306 SetMouseMode(MouseMode_TrackCoordinates, statusBar);
307 break;
308
309 case 'm':
310 SetMouseMode(MouseMode_LineMeasure, statusBar);
311 break;
312
313 case 'c':
314 SetMouseMode(MouseMode_CircleMeasure, statusBar);
315 break;
316
317 case 'b':
318 {
319 if (statusBar)
320 {
321 statusBar->SetMessage("Setting Hounsfield window to bones");
322 }
323
324 RenderStyle style;
325 style.windowing_ = ImageWindowing_Bone;
326 dynamic_cast<LayeredSceneWidget&>(widget).SetLayerStyle(0, style);
327 break;
328 }
329
330 case 'l':
331 {
332 if (statusBar)
333 {
334 statusBar->SetMessage("Setting Hounsfield window to lung");
335 }
336
337 RenderStyle style;
338 style.windowing_ = ImageWindowing_Lung;
339 dynamic_cast<LayeredSceneWidget&>(widget).SetLayerStyle(0, style);
340 break;
341 }
342
343 case 'd':
344 {
345 if (statusBar)
346 {
347 statusBar->SetMessage("Setting Hounsfield window to what is written in the DICOM file");
348 }
349
350 RenderStyle style;
351 style.windowing_ = ImageWindowing_Default;
352 dynamic_cast<LayeredSceneWidget&>(widget).SetLayerStyle(0, style);
353 break;
354 }
355
356 default:
357 break;
358 }
359 }
360 };
361 #endif
362
363
364 public: 41 public:
365 SingleVolumeApplication() :
366 widget_(NULL),
367 volume_(NULL)
368 {
369 }
370
371 virtual void DeclareCommandLineOptions(boost::program_options::options_description& options) 42 virtual void DeclareCommandLineOptions(boost::program_options::options_description& options)
372 { 43 {
373 boost::program_options::options_description generic("Sample options"); 44 boost::program_options::options_description generic("Sample options");
374 generic.add_options() 45 generic.add_options()
375 ("series", boost::program_options::value<std::string>(), 46 ("series", boost::program_options::value<std::string>(),
401 unsigned int threads = parameters["threads"].as<unsigned int>(); 72 unsigned int threads = parameters["threads"].as<unsigned int>();
402 bool reverse = parameters["reverse"].as<bool>(); 73 bool reverse = parameters["reverse"].as<bool>();
403 74
404 std::string tmp = parameters["projection"].as<std::string>(); 75 std::string tmp = parameters["projection"].as<std::string>();
405 Orthanc::Toolbox::ToLowerCase(tmp); 76 Orthanc::Toolbox::ToLowerCase(tmp);
406 77
78 VolumeProjection projection;
407 if (tmp == "axial") 79 if (tmp == "axial")
408 { 80 {
409 projection_ = VolumeProjection_Axial; 81 projection = VolumeProjection_Axial;
410 } 82 }
411 else if (tmp == "sagittal") 83 else if (tmp == "sagittal")
412 { 84 {
413 projection_ = VolumeProjection_Sagittal; 85 projection = VolumeProjection_Sagittal;
414 } 86 }
415 else if (tmp == "coronal") 87 else if (tmp == "coronal")
416 { 88 {
417 projection_ = VolumeProjection_Coronal; 89 projection = VolumeProjection_Coronal;
418 } 90 }
419 else 91 else
420 { 92 {
421 LOG(ERROR) << "Unknown projection: " << tmp; 93 LOG(ERROR) << "Unknown projection: " << tmp;
422 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 94 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
423 } 95 }
424 96
425 std::auto_ptr<LayerWidget> widget(new LayerWidget); 97 std::auto_ptr<LayerWidget> widget(new LayerWidget);
426 widget_ = widget.get();
427 98
428 #if 0 99 #if 1
429 std::auto_ptr<OrthancVolumeImage> volume(new OrthancVolumeImage(context.GetWebService())); 100 std::auto_ptr<OrthancVolumeImage> volume(new OrthancVolumeImage(context.GetWebService()));
430 volume->ScheduleLoadSeries(series); 101 volume->ScheduleLoadSeries(series);
431 102
432 volume_ = volume.get();
433
434 { 103 {
435 std::auto_ptr<VolumeImageSource> source(new VolumeImageSource(*volume)); 104 std::auto_ptr<VolumeImageSource> source(new VolumeImageSource(*volume));
436 source->Register(*this);
437 widget->AddLayer(source.release()); 105 widget->AddLayer(source.release());
438 } 106 }
439 107
108 context.AddInteractor(new VolumeImageInteractor(*volume, *widget, projection));
440 context.AddVolume(volume.release()); 109 context.AddVolume(volume.release());
441 #else 110 #else
442 std::auto_ptr<OrthancVolumeImage> ct(new OrthancVolumeImage(context.GetWebService())); 111 std::auto_ptr<OrthancVolumeImage> ct(new OrthancVolumeImage(context.GetWebService()));
443 ct->ScheduleLoadSeries("dd069910-4f090474-7d2bba07-e5c10783-f9e4fb1d"); 112 ct->ScheduleLoadSeries("dd069910-4f090474-7d2bba07-e5c10783-f9e4fb1d");
444 113
445 std::auto_ptr<OrthancVolumeImage> pet(new OrthancVolumeImage(context.GetWebService())); 114 std::auto_ptr<OrthancVolumeImage> pet(new OrthancVolumeImage(context.GetWebService()));
446 pet->ScheduleLoadSeries("aabad2e7-80702b5d-e599d26c-4f13398e-38d58a9e"); 115 pet->ScheduleLoadSeries("aabad2e7-80702b5d-e599d26c-4f13398e-38d58a9e");
447 116
448 volume_ = pet.get(); 117 context.AddInteractor(new VolumeImageInteractor(*pet, *widget, projection));
449 118
450 { 119 {
451 std::auto_ptr<VolumeImageSource> source(new VolumeImageSource(*ct)); 120 std::auto_ptr<VolumeImageSource> source(new VolumeImageSource(*ct));
452 //source->Register(*this);
453 widget->AddLayer(source.release()); 121 widget->AddLayer(source.release());
454 } 122 }
455 123
456 { 124 {
457 std::auto_ptr<VolumeImageSource> source(new VolumeImageSource(*pet)); 125 std::auto_ptr<VolumeImageSource> source(new VolumeImageSource(*pet));
458 source->Register(*this);
459 widget->AddLayer(source.release()); 126 widget->AddLayer(source.release());
460 } 127 }
461 128
462 context.AddVolume(ct.release()); 129 context.AddVolume(ct.release());
463 context.AddVolume(pet.release()); 130 context.AddVolume(pet.release());
464 131
465 { 132 {
466 RenderStyle s; 133 RenderStyle s;
467 //s.drawGrid_ = true; 134 //s.drawGrid_ = true;
468 s.alpha_ = 1; 135 s.alpha_ = 1;
136 s.windowing_ = ImageWindowing_Bone;
469 widget->SetLayerStyle(0, s); 137 widget->SetLayerStyle(0, s);
470 } 138 }
471 139
472 { 140 {
473 RenderStyle s; 141 RenderStyle s;
474 //s.drawGrid_ = true; 142 //s.drawGrid_ = true;
475 s.SetColor(255, 0, 0); // Draw missing PET layer in red 143 s.SetColor(255, 0, 0); // Draw missing PET layer in red
476 s.alpha_ = 0.5; 144 s.alpha_ = 0.3;
477 s.applyLut_ = true; 145 s.applyLut_ = true;
478 s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET; 146 s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET;
479 s.interpolation_ = ImageInterpolation_Linear; 147 s.interpolation_ = ImageInterpolation_Linear;
480 widget->SetLayerStyle(1, s); 148 widget->SetLayerStyle(1, s);
481 } 149 }
486 statusBar.SetMessage("Use the keys \"t\" to track the (X,Y,Z) mouse coordinates"); 154 statusBar.SetMessage("Use the keys \"t\" to track the (X,Y,Z) mouse coordinates");
487 statusBar.SetMessage("Use the keys \"m\" to measure distances"); 155 statusBar.SetMessage("Use the keys \"m\" to measure distances");
488 statusBar.SetMessage("Use the keys \"c\" to draw circles"); 156 statusBar.SetMessage("Use the keys \"c\" to draw circles");
489 157
490 widget->SetTransmitMouseOver(true); 158 widget->SetTransmitMouseOver(true);
491 widget->SetInteractor(context.AddInteractor(new Interactor(*this)));
492 context.SetCentralWidget(widget.release()); 159 context.SetCentralWidget(widget.release());
493 } 160 }
494 }; 161 };
495 } 162 }
496 } 163 }