Mercurial > hg > orthanc-stone
annotate Applications/Samples/SimpleViewerApplication.h @ 250:5e642859267e am-2
added new Observable/Observer & MessageBroker (not used yet)
author | am@osimis.io |
---|---|
date | Mon, 02 Jul 2018 16:36:17 +0200 |
parents | 54c7284b0eff |
children | 192e6e349e69 |
rev | line source |
---|---|
235 | 1 /** |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2018 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
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. | |
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 | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
249 | 16 * |
235 | 17 * You should have received a copy of the GNU Affero General Public License |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 | |
22 #pragma once | |
23 | |
24 #include "SampleApplicationBase.h" | |
25 | |
26 #include "../../Framework/Layers/OrthancFrameLayerSource.h" | |
27 #include "../../Framework/Widgets/LayerWidget.h" | |
28 #include "../../Framework/Widgets/LayoutWidget.h" | |
29 | |
30 #include <Core/Logging.h> | |
31 | |
32 namespace OrthancStone | |
33 { | |
34 namespace Samples | |
35 { | |
36 class SimpleViewerApplication : | |
249 | 37 public SampleApplicationBase, |
38 private ILayerSource::IObserver | |
235 | 39 { |
40 private: | |
41 class Interactor : public IWorldSceneInteractor | |
42 { | |
43 private: | |
44 SimpleViewerApplication& application_; | |
45 | |
46 public: | |
47 Interactor(SimpleViewerApplication& application) : | |
48 application_(application) | |
49 { | |
50 } | |
51 | |
52 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, | |
53 const ViewportGeometry& view, | |
54 MouseButton button, | |
55 double x, | |
56 double y, | |
57 IStatusBar* statusBar) | |
58 { | |
59 return NULL; | |
60 } | |
61 | |
62 virtual void MouseOver(CairoContext& context, | |
63 WorldSceneWidget& widget, | |
64 const ViewportGeometry& view, | |
65 double x, | |
66 double y, | |
67 IStatusBar* statusBar) | |
68 { | |
69 if (statusBar != NULL) | |
70 { | |
71 Vector p = dynamic_cast<LayerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y); | |
72 | |
73 char buf[64]; | |
249 | 74 sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)", |
235 | 75 p[0] / 10.0, p[1] / 10.0, p[2] / 10.0); |
76 statusBar->SetMessage(buf); | |
77 } | |
78 } | |
79 | |
80 virtual void MouseWheel(WorldSceneWidget& widget, | |
81 MouseWheelDirection direction, | |
82 KeyboardModifiers modifiers, | |
83 IStatusBar* statusBar) | |
84 { | |
249 | 85 // int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1); |
235 | 86 |
249 | 87 // switch (direction) |
88 // { | |
89 // case MouseWheelDirection_Up: | |
90 // application_.OffsetSlice(-scale); | |
91 // break; | |
235 | 92 |
249 | 93 // case MouseWheelDirection_Down: |
94 // application_.OffsetSlice(scale); | |
95 // break; | |
235 | 96 |
249 | 97 // default: |
98 // break; | |
99 // } | |
235 | 100 } |
101 | |
102 virtual void KeyPressed(WorldSceneWidget& widget, | |
103 char key, | |
104 KeyboardModifiers modifiers, | |
105 IStatusBar* statusBar) | |
106 { | |
107 switch (key) | |
108 { | |
249 | 109 case 's': |
110 widget.SetDefaultView(); | |
111 break; | |
112 case 'n': | |
113 application_.NextImage(widget); | |
114 break; | |
235 | 115 |
249 | 116 default: |
117 break; | |
235 | 118 } |
119 } | |
120 }; | |
121 | |
122 | |
249 | 123 // void OffsetSlice(int offset) |
124 // { | |
125 // if (source_ != NULL) | |
126 // { | |
127 // int slice = static_cast<int>(slice_) + offset; | |
235 | 128 |
249 | 129 // if (slice < 0) |
130 // { | |
131 // slice = 0; | |
132 // } | |
235 | 133 |
249 | 134 // if (slice >= static_cast<int>(source_->GetSliceCount())) |
135 // { | |
136 // slice = source_->GetSliceCount() - 1; | |
137 // } | |
235 | 138 |
249 | 139 // if (slice != static_cast<int>(slice_)) |
140 // { | |
141 // SetSlice(slice); | |
142 // } | |
143 // } | |
144 // } | |
235 | 145 |
146 | |
249 | 147 // void SetSlice(size_t index) |
148 // { | |
149 // if (source_ != NULL && | |
150 // index < source_->GetSliceCount()) | |
151 // { | |
152 // slice_ = index; | |
153 | |
154 //#if 1 | |
155 // widget_->SetSlice(source_->GetSlice(slice_).GetGeometry()); | |
156 //#else | |
157 // // TEST for scene extents - Rotate the axes | |
158 // double a = 15.0 / 180.0 * M_PI; | |
235 | 159 |
249 | 160 //#if 1 |
161 // Vector x; GeometryToolbox::AssignVector(x, cos(a), sin(a), 0); | |
162 // Vector y; GeometryToolbox::AssignVector(y, -sin(a), cos(a), 0); | |
163 //#else | |
164 // // Flip the normal | |
165 // Vector x; GeometryToolbox::AssignVector(x, cos(a), sin(a), 0); | |
166 // Vector y; GeometryToolbox::AssignVector(y, sin(a), -cos(a), 0); | |
167 //#endif | |
168 | |
169 // SliceGeometry s(source_->GetSlice(slice_).GetGeometry().GetOrigin(), x, y); | |
170 // widget_->SetSlice(s); | |
171 //#endif | |
172 // } | |
173 // } | |
174 | |
235 | 175 |
176 virtual void NotifyGeometryReady(const ILayerSource& source) | |
177 { | |
178 // Once the geometry of the series is downloaded from Orthanc, | |
179 // display its first slice, and adapt the viewport to fit this | |
180 // slice | |
181 if (source_ == &source) | |
182 { | |
183 //SetSlice(source_->GetSliceCount() / 2); | |
184 } | |
185 | |
186 mainLayout_->SetDefaultView(); | |
187 } | |
188 | |
189 virtual void NotifyGeometryError(const ILayerSource& source) | |
190 { | |
191 } | |
192 | |
193 virtual void NotifyContentChange(const ILayerSource& source) | |
194 { | |
195 } | |
196 | |
197 virtual void NotifySliceChange(const ILayerSource& source, | |
198 const Slice& slice) | |
199 { | |
200 } | |
249 | 201 |
235 | 202 virtual void NotifyLayerReady(std::auto_ptr<ILayerRenderer>& layer, |
203 const ILayerSource& source, | |
204 const CoordinateSystem3D& slice, | |
205 bool isError) | |
206 { | |
207 } | |
208 | |
242 | 209 std::unique_ptr<Interactor> interactor_; |
235 | 210 LayoutWidget* mainLayout_; |
211 LayoutWidget* thumbnailsLayout_; | |
212 LayerWidget* mainViewport_; | |
213 std::vector<LayerWidget*> thumbnails_; | |
214 std::vector<std::string> instances_; | |
215 unsigned int currentInstanceIndex_; | |
237
b4642964c355
SimpleViewer demo running both with SDL and Wasm
am@osimis.io
parents:
235
diff
changeset
|
216 OrthancStone::WidgetViewport* wasmViewport1_; |
b4642964c355
SimpleViewer demo running both with SDL and Wasm
am@osimis.io
parents:
235
diff
changeset
|
217 OrthancStone::WidgetViewport* wasmViewport2_; |
235 | 218 |
219 OrthancFrameLayerSource* source_; | |
220 unsigned int slice_; | |
221 | |
222 public: | |
242 | 223 SimpleViewerApplication() : |
235 | 224 mainLayout_(NULL), |
225 currentInstanceIndex_(0), | |
226 source_(NULL), | |
237
b4642964c355
SimpleViewer demo running both with SDL and Wasm
am@osimis.io
parents:
235
diff
changeset
|
227 slice_(0), |
242 | 228 wasmViewport1_(NULL), |
229 wasmViewport2_(NULL) | |
235 | 230 { |
231 } | |
232 | |
237
b4642964c355
SimpleViewer demo running both with SDL and Wasm
am@osimis.io
parents:
235
diff
changeset
|
233 virtual void Finalize() {} |
b4642964c355
SimpleViewer demo running both with SDL and Wasm
am@osimis.io
parents:
235
diff
changeset
|
234 virtual IWidget* GetCentralWidget() {return mainLayout_;} |
b4642964c355
SimpleViewer demo running both with SDL and Wasm
am@osimis.io
parents:
235
diff
changeset
|
235 |
235 | 236 virtual void DeclareStartupOptions(boost::program_options::options_description& options) |
237 { | |
238 boost::program_options::options_description generic("Sample options"); | |
239 generic.add_options() | |
249 | 240 // ("study", boost::program_options::value<std::string>(), |
241 // "Orthanc ID of the study") | |
242 ("instance1", boost::program_options::value<std::string>(), | |
243 "Orthanc ID of the instances") | |
235 | 244 ("instance2", boost::program_options::value<std::string>(), |
245 "Orthanc ID of the instances") | |
249 | 246 ; |
235 | 247 |
249 | 248 options.add(generic); |
235 | 249 } |
250 | |
242 | 251 virtual void Initialize(BasicApplicationContext* context, |
252 IStatusBar& statusBar, | |
235 | 253 const boost::program_options::variables_map& parameters) |
254 { | |
255 using namespace OrthancStone; | |
256 | |
242 | 257 context_ = context; |
235 | 258 statusBar.SetMessage("Use the key \"s\" to reinitialize the layout"); |
259 | |
260 if (parameters.count("instance1") < 1) | |
261 { | |
262 LOG(ERROR) << "The instance ID is missing"; | |
263 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
264 } | |
265 if (parameters.count("instance2") < 1) | |
266 { | |
267 LOG(ERROR) << "The instance ID is missing"; | |
268 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
269 } | |
270 instances_.push_back(parameters["instance1"].as<std::string>()); | |
271 instances_.push_back(parameters["instance2"].as<std::string>()); | |
272 | |
273 mainLayout_ = new LayoutWidget(); | |
274 mainLayout_->SetPadding(10); | |
275 mainLayout_->SetBackgroundCleared(true); | |
276 mainLayout_->SetBackgroundColor(0, 0, 0); | |
277 mainLayout_->SetHorizontal(); | |
278 | |
279 thumbnailsLayout_ = new LayoutWidget(); | |
280 thumbnailsLayout_->SetPadding(10); | |
281 thumbnailsLayout_->SetBackgroundCleared(true); | |
282 thumbnailsLayout_->SetBackgroundColor(50, 50, 50); | |
283 thumbnailsLayout_->SetVertical(); | |
284 | |
285 mainViewport_ = new LayerWidget(); | |
286 thumbnails_.push_back(new LayerWidget()); | |
287 thumbnails_.push_back(new LayerWidget()); | |
288 | |
289 // hierarchy | |
290 mainLayout_->AddWidget(thumbnailsLayout_); | |
291 mainLayout_->AddWidget(mainViewport_); | |
292 thumbnailsLayout_->AddWidget(thumbnails_[0]); | |
293 thumbnailsLayout_->AddWidget(thumbnails_[1]); | |
294 | |
295 // sources | |
296 source_ = new OrthancFrameLayerSource(context_->GetWebService()); | |
297 source_->LoadFrame(instances_[currentInstanceIndex_], 0); | |
245 | 298 source_->Register(*this); |
235 | 299 |
300 mainViewport_->AddLayer(source_); | |
301 | |
302 OrthancFrameLayerSource* thumb0 = new OrthancFrameLayerSource(context_->GetWebService()); | |
303 thumb0->LoadFrame(instances_[0], 0); | |
304 OrthancFrameLayerSource* thumb1 = new OrthancFrameLayerSource(context_->GetWebService()); | |
305 thumb1->LoadFrame(instances_[1], 0); | |
306 | |
307 thumbnails_[0]->AddLayer(thumb0); | |
308 thumbnails_[1]->AddLayer(thumb1); | |
309 | |
310 mainLayout_->SetTransmitMouseOver(true); | |
242 | 311 interactor_.reset(new Interactor(*this)); |
312 mainViewport_->SetInteractor(*interactor_); | |
313 } | |
237
b4642964c355
SimpleViewer demo running both with SDL and Wasm
am@osimis.io
parents:
235
diff
changeset
|
314 |
242 | 315 #if ORTHANC_ENABLE_SDL==0 |
316 virtual void InitializeWasm() { | |
317 | |
318 AttachWidgetToWasmViewport("canvas", thumbnailsLayout_); | |
319 AttachWidgetToWasmViewport("canvas2", mainViewport_); | |
320 } | |
237
b4642964c355
SimpleViewer demo running both with SDL and Wasm
am@osimis.io
parents:
235
diff
changeset
|
321 #endif |
249 | 322 |
323 void NextImage(WorldSceneWidget& widget) { | |
324 assert(context_); | |
325 | |
326 currentInstanceIndex_ = (currentInstanceIndex_ + 1) % instances_.size(); | |
327 | |
328 std::auto_ptr<OrthancFrameLayerSource> layer | |
329 (new OrthancFrameLayerSource(context_->GetWebService())); | |
330 layer->LoadFrame(instances_[currentInstanceIndex_], 0); | |
331 | |
332 mainViewport_->ReplaceLayer(0, layer.release()); | |
333 // source_->LoadFrame("45b7e6bc-168e8ed1-063dc08d-cffd6431-133a276a", 0); | |
334 } | |
235 | 335 }; |
249 | 336 |
337 | |
235 | 338 } |
339 } |