Mercurial > hg > orthanc-stone
annotate Applications/Samples/SingleVolumeApplication.h @ 51:b340879da9bd
reorganization
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 27 Apr 2017 14:50:20 +0200 |
parents | Samples/SingleVolumeApplication.h@28956ed68280 |
children | fcec0ab44054 4cff7b1ed31d |
rev | line source |
---|---|
0 | 1 /** |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
40
7207a407bcd8
shared copyright with osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
5 * Copyright (C) 2017 Osimis, Belgium |
0 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
47 | 8 * modify it under the terms of the GNU Affero General Public License |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
0 | 11 * |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
47 | 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
0 | 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 **/ | |
20 | |
21 | |
22 #pragma once | |
23 | |
24 #include "SampleInteractor.h" | |
25 | |
51 | 26 #include "../../Resources/Orthanc/Core/Toolbox.h" |
27 #include "../../Framework/Layers/LineMeasureTracker.h" | |
28 #include "../../Framework/Layers/CircleMeasureTracker.h" | |
29 #include "../../Resources/Orthanc/Core/Logging.h" | |
0 | 30 |
31 namespace OrthancStone | |
32 { | |
33 namespace Samples | |
34 { | |
35 class SingleVolumeApplication : public SampleApplicationBase | |
36 { | |
37 private: | |
38 class Interactor : public SampleInteractor | |
39 { | |
40 private: | |
41 enum MouseMode | |
42 { | |
43 MouseMode_None, | |
44 MouseMode_TrackCoordinates, | |
45 MouseMode_LineMeasure, | |
46 MouseMode_CircleMeasure | |
47 }; | |
48 | |
49 MouseMode mouseMode_; | |
50 | |
51 void SetMouseMode(MouseMode mode, | |
52 IStatusBar* statusBar) | |
53 { | |
54 if (mouseMode_ == mode) | |
55 { | |
56 mouseMode_ = MouseMode_None; | |
57 } | |
58 else | |
59 { | |
60 mouseMode_ = mode; | |
61 } | |
62 | |
63 if (statusBar) | |
64 { | |
65 switch (mouseMode_) | |
66 { | |
67 case MouseMode_None: | |
68 statusBar->SetMessage("Disabling the mouse tools"); | |
69 break; | |
70 | |
71 case MouseMode_TrackCoordinates: | |
72 statusBar->SetMessage("Tracking the mouse coordinates"); | |
73 break; | |
74 | |
75 case MouseMode_LineMeasure: | |
76 statusBar->SetMessage("Mouse clicks will now measure the distances"); | |
77 break; | |
78 | |
79 case MouseMode_CircleMeasure: | |
80 statusBar->SetMessage("Mouse clicks will now draw circles"); | |
81 break; | |
82 | |
83 default: | |
84 break; | |
85 } | |
86 } | |
87 } | |
88 | |
89 public: | |
90 Interactor(VolumeImage& volume, | |
91 VolumeProjection projection, | |
92 bool reverse) : | |
93 SampleInteractor(volume, projection, reverse), | |
94 mouseMode_(MouseMode_None) | |
95 { | |
96 } | |
97 | |
98 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, | |
99 const SliceGeometry& slice, | |
100 const ViewportGeometry& view, | |
101 MouseButton button, | |
102 double x, | |
103 double y, | |
104 IStatusBar* statusBar) | |
105 { | |
106 if (button == MouseButton_Left) | |
107 { | |
108 switch (mouseMode_) | |
109 { | |
110 case MouseMode_LineMeasure: | |
111 return new LineMeasureTracker(NULL, slice, x, y, 255, 0, 0, 14 /* font size */); | |
112 | |
113 case MouseMode_CircleMeasure: | |
114 return new CircleMeasureTracker(NULL, slice, x, y, 255, 0, 0, 14 /* font size */); | |
115 | |
116 default: | |
117 break; | |
118 } | |
119 } | |
120 | |
121 return NULL; | |
122 } | |
123 | |
124 virtual void MouseOver(CairoContext& context, | |
125 WorldSceneWidget& widget, | |
126 const SliceGeometry& slice, | |
127 const ViewportGeometry& view, | |
128 double x, | |
129 double y, | |
130 IStatusBar* statusBar) | |
131 { | |
132 if (mouseMode_ == MouseMode_TrackCoordinates && | |
133 statusBar != NULL) | |
134 { | |
135 Vector p = slice.MapSliceToWorldCoordinates(x, y); | |
136 | |
137 char buf[64]; | |
138 sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)", p[0] / 10.0, p[1] / 10.0, p[2] / 10.0); | |
139 statusBar->SetMessage(buf); | |
140 } | |
141 } | |
142 | |
143 | |
144 virtual void KeyPressed(WorldSceneWidget& widget, | |
145 char key, | |
146 KeyboardModifiers modifiers, | |
147 IStatusBar* statusBar) | |
148 { | |
149 switch (key) | |
150 { | |
151 case 't': | |
152 SetMouseMode(MouseMode_TrackCoordinates, statusBar); | |
153 break; | |
154 | |
155 case 'm': | |
156 SetMouseMode(MouseMode_LineMeasure, statusBar); | |
157 break; | |
158 | |
159 case 'c': | |
160 SetMouseMode(MouseMode_CircleMeasure, statusBar); | |
161 break; | |
162 | |
163 case 'b': | |
164 { | |
165 if (statusBar) | |
166 { | |
167 statusBar->SetMessage("Setting Hounsfield window to bones"); | |
168 } | |
169 | |
170 RenderStyle style; | |
171 style.windowing_ = ImageWindowing_Bone; | |
172 dynamic_cast<LayeredSceneWidget&>(widget).SetLayerStyle(0, style); | |
173 break; | |
174 } | |
175 | |
176 case 'l': | |
177 { | |
178 if (statusBar) | |
179 { | |
180 statusBar->SetMessage("Setting Hounsfield window to lung"); | |
181 } | |
182 | |
183 RenderStyle style; | |
184 style.windowing_ = ImageWindowing_Lung; | |
185 dynamic_cast<LayeredSceneWidget&>(widget).SetLayerStyle(0, style); | |
186 break; | |
187 } | |
188 | |
189 case 'd': | |
190 { | |
191 if (statusBar) | |
192 { | |
193 statusBar->SetMessage("Setting Hounsfield window to what is written in the DICOM file"); | |
194 } | |
195 | |
196 RenderStyle style; | |
197 style.windowing_ = ImageWindowing_Default; | |
198 dynamic_cast<LayeredSceneWidget&>(widget).SetLayerStyle(0, style); | |
199 break; | |
200 } | |
201 | |
202 default: | |
203 break; | |
204 } | |
205 } | |
206 }; | |
207 | |
208 | |
209 public: | |
210 virtual void DeclareCommandLineOptions(boost::program_options::options_description& options) | |
211 { | |
212 boost::program_options::options_description generic("Sample options"); | |
213 generic.add_options() | |
214 ("series", boost::program_options::value<std::string>(), | |
215 "Orthanc ID of the series") | |
216 ("threads", boost::program_options::value<unsigned int>()->default_value(3), | |
217 "Number of download threads") | |
218 ("projection", boost::program_options::value<std::string>()->default_value("axial"), | |
219 "Projection of interest (can be axial, sagittal or coronal)") | |
220 ("reverse", boost::program_options::value<bool>()->default_value(false), | |
221 "Reverse the normal direction of the volume") | |
222 ; | |
223 | |
224 options.add(generic); | |
225 } | |
226 | |
227 virtual void Initialize(BasicApplicationContext& context, | |
228 IStatusBar& statusBar, | |
229 const boost::program_options::variables_map& parameters) | |
230 { | |
231 using namespace OrthancStone; | |
232 | |
233 if (parameters.count("series") != 1) | |
234 { | |
235 LOG(ERROR) << "The series ID is missing"; | |
236 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
237 } | |
238 | |
239 std::string series = parameters["series"].as<std::string>(); | |
240 unsigned int threads = parameters["threads"].as<unsigned int>(); | |
241 bool reverse = parameters["reverse"].as<bool>(); | |
242 | |
243 std::string tmp = parameters["projection"].as<std::string>(); | |
244 Orthanc::Toolbox::ToLowerCase(tmp); | |
245 | |
246 VolumeProjection projection; | |
247 if (tmp == "axial") | |
248 { | |
249 projection = VolumeProjection_Axial; | |
250 } | |
251 else if (tmp == "sagittal") | |
252 { | |
253 projection = VolumeProjection_Sagittal; | |
254 } | |
255 else if (tmp == "coronal") | |
256 { | |
257 projection = VolumeProjection_Coronal; | |
258 } | |
259 else | |
260 { | |
261 LOG(ERROR) << "Unknown projection: " << tmp; | |
262 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
263 } | |
264 | |
265 VolumeImage& volume = context.AddSeriesVolume(series, true /* progressive download */, threads); | |
266 | |
267 std::auto_ptr<Interactor> interactor(new Interactor(volume, projection, reverse)); | |
268 | |
269 std::auto_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget); | |
270 widget->AddLayer(new VolumeImage::LayerFactory(volume)); | |
271 widget->SetSlice(interactor->GetCursor().GetCurrentSlice()); | |
272 widget->SetInteractor(*interactor); | |
273 | |
274 context.AddInteractor(interactor.release()); | |
275 context.SetCentralWidget(widget.release()); | |
276 | |
277 statusBar.SetMessage("Use the keys \"b\", \"l\" and \"d\" to change Hounsfield windowing"); | |
278 statusBar.SetMessage("Use the keys \"t\" to track the (X,Y,Z) mouse coordinates"); | |
279 statusBar.SetMessage("Use the keys \"m\" to measure distances"); | |
280 statusBar.SetMessage("Use the keys \"c\" to draw circles"); | |
281 } | |
282 }; | |
283 } | |
284 } |