comparison Resources/Graveyard/Deprecated/Samples/WebAssembly/BasicMPR.cpp @ 1503:553084468225

moving /Deprecated/ to /Resources/Graveyard/Deprecated/
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 30 Jun 2020 11:38:13 +0200
parents Deprecated/Samples/WebAssembly/BasicMPR.cpp@65e1e4b08302
children
comparison
equal deleted inserted replaced
1502:e5729dab3f67 1503:553084468225
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-2020 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.
16 *
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
23 #include "dev.h"
24
25 #include <emscripten.h>
26
27 #include "../../Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h"
28 #include "../../Framework/Oracle/SleepOracleCommand.h"
29 #include "../../Framework/Oracle/WebAssemblyOracle.h"
30 #include "../../Framework/Scene2D/GrayscaleStyleConfigurator.h"
31 #include "../../Framework/StoneInitialization.h"
32 #include "../../Framework/Volumes/VolumeSceneLayerSource.h"
33
34
35 namespace OrthancStone
36 {
37 class VolumeSlicerWidget : public IObserver
38 {
39 private:
40 OrthancStone::WebAssemblyViewport viewport_;
41 std::unique_ptr<VolumeSceneLayerSource> source_;
42 VolumeProjection projection_;
43 std::vector<CoordinateSystem3D> planes_;
44 size_t currentPlane_;
45
46 void Handle(const DicomVolumeImage::GeometryReadyMessage& message)
47 {
48 LOG(INFO) << "Geometry is available";
49
50 const VolumeImageGeometry& geometry = message.GetOrigin().GetGeometry();
51
52 const unsigned int depth = geometry.GetProjectionDepth(projection_);
53 currentPlane_ = depth / 2;
54
55 planes_.resize(depth);
56
57 for (unsigned int z = 0; z < depth; z++)
58 {
59 planes_[z] = geometry.GetProjectionSlice(projection_, z);
60 }
61
62 Refresh();
63
64 viewport_.FitContent();
65 }
66
67 public:
68 VolumeSlicerWidget(MessageBroker& broker,
69 const std::string& canvas,
70 VolumeProjection projection) :
71 IObserver(broker),
72 viewport_(broker, canvas),
73 projection_(projection),
74 currentPlane_(0)
75 {
76 }
77
78 void UpdateSize()
79 {
80 viewport_.UpdateSize();
81 }
82
83 void SetSlicer(int layerDepth,
84 const boost::shared_ptr<IVolumeSlicer>& slicer,
85 IObservable& loader,
86 ILayerStyleConfigurator* configurator)
87 {
88 if (source_.get() != NULL)
89 {
90 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls,
91 "Only one slicer can be registered");
92 }
93
94 loader.RegisterObserverCallback(
95 new Callable<VolumeSlicerWidget, DicomVolumeImage::GeometryReadyMessage>
96 (*this, &VolumeSlicerWidget::Handle));
97
98 source_.reset(new VolumeSceneLayerSource(viewport_.GetScene(), layerDepth, slicer));
99
100 if (configurator != NULL)
101 {
102 source_->SetConfigurator(configurator);
103 }
104 }
105
106 void Refresh()
107 {
108 if (source_.get() != NULL &&
109 currentPlane_ < planes_.size())
110 {
111 source_->Update(planes_[currentPlane_]);
112 viewport_.Refresh();
113 }
114 }
115
116 size_t GetSlicesCount() const
117 {
118 return planes_.size();
119 }
120
121 void Scroll(int delta)
122 {
123 if (!planes_.empty())
124 {
125 int tmp = static_cast<int>(currentPlane_) + delta;
126 unsigned int next;
127
128 if (tmp < 0)
129 {
130 next = 0;
131 }
132 else if (tmp >= static_cast<int>(planes_.size()))
133 {
134 next = planes_.size() - 1;
135 }
136 else
137 {
138 next = static_cast<size_t>(tmp);
139 }
140
141 if (next != currentPlane_)
142 {
143 currentPlane_ = next;
144 Refresh();
145 }
146 }
147 }
148 };
149 }
150
151
152
153
154 boost::shared_ptr<OrthancStone::DicomVolumeImage> ct_(new OrthancStone::DicomVolumeImage);
155
156 boost::shared_ptr<OrthancStone::OrthancSeriesVolumeProgressiveLoader> loader_;
157
158 std::unique_ptr<OrthancStone::VolumeSlicerWidget> widget1_;
159 std::unique_ptr<OrthancStone::VolumeSlicerWidget> widget2_;
160 std::unique_ptr<OrthancStone::VolumeSlicerWidget> widget3_;
161
162 OrthancStone::MessageBroker broker_;
163 OrthancStone::WebAssemblyOracle oracle_(broker_);
164
165
166 EM_BOOL OnWindowResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)
167 {
168 try
169 {
170 if (widget1_.get() != NULL)
171 {
172 widget1_->UpdateSize();
173 }
174
175 if (widget2_.get() != NULL)
176 {
177 widget2_->UpdateSize();
178 }
179
180 if (widget3_.get() != NULL)
181 {
182 widget3_->UpdateSize();
183 }
184 }
185 catch (Orthanc::OrthancException& e)
186 {
187 LOG(ERROR) << "Exception while updating canvas size: " << e.What();
188 }
189
190 return true;
191 }
192
193
194
195
196 EM_BOOL OnAnimationFrame(double time, void *userData)
197 {
198 try
199 {
200 if (widget1_.get() != NULL)
201 {
202 widget1_->Refresh();
203 }
204
205 if (widget2_.get() != NULL)
206 {
207 widget2_->Refresh();
208 }
209
210 if (widget3_.get() != NULL)
211 {
212 widget3_->Refresh();
213 }
214
215 return true;
216 }
217 catch (Orthanc::OrthancException& e)
218 {
219 LOG(ERROR) << "Exception in the animation loop, stopping now: " << e.What();
220 return false;
221 }
222 }
223
224
225 static bool ctrlDown_ = false;
226
227
228 EM_BOOL OnMouseWheel(int eventType,
229 const EmscriptenWheelEvent *wheelEvent,
230 void *userData)
231 {
232 try
233 {
234 if (userData != NULL)
235 {
236 int delta = 0;
237
238 if (wheelEvent->deltaY < 0)
239 {
240 delta = -1;
241 }
242
243 if (wheelEvent->deltaY > 0)
244 {
245 delta = 1;
246 }
247
248 OrthancStone::VolumeSlicerWidget& widget =
249 *reinterpret_cast<OrthancStone::VolumeSlicerWidget*>(userData);
250
251 if (ctrlDown_)
252 {
253 delta *= static_cast<int>(widget.GetSlicesCount() / 10);
254 }
255
256 widget.Scroll(delta);
257 }
258 }
259 catch (Orthanc::OrthancException& e)
260 {
261 LOG(ERROR) << "Exception in the wheel event: " << e.What();
262 }
263
264 return true;
265 }
266
267
268 EM_BOOL OnKeyDown(int eventType,
269 const EmscriptenKeyboardEvent *keyEvent,
270 void *userData)
271 {
272 ctrlDown_ = keyEvent->ctrlKey;
273 return false;
274 }
275
276
277 EM_BOOL OnKeyUp(int eventType,
278 const EmscriptenKeyboardEvent *keyEvent,
279 void *userData)
280 {
281 ctrlDown_ = false;
282 return false;
283 }
284
285
286
287
288 namespace OrthancStone
289 {
290 class TestSleep : public IObserver
291 {
292 private:
293 WebAssemblyOracle& oracle_;
294
295 void Schedule()
296 {
297 oracle_.Schedule(*this, new OrthancStone::SleepOracleCommand(2000));
298 }
299
300 void Handle(const SleepOracleCommand::TimeoutMessage& message)
301 {
302 LOG(INFO) << "TIMEOUT";
303 Schedule();
304 }
305
306 public:
307 TestSleep(MessageBroker& broker,
308 WebAssemblyOracle& oracle) :
309 IObserver(broker),
310 oracle_(oracle)
311 {
312 oracle.RegisterObserverCallback(
313 new Callable<TestSleep, SleepOracleCommand::TimeoutMessage>
314 (*this, &TestSleep::Handle));
315
316 LOG(INFO) << "STARTING";
317 Schedule();
318 }
319 };
320
321 //static TestSleep testSleep(broker_, oracle_);
322 }
323
324
325
326 static std::map<std::string, std::string> arguments_;
327
328 static bool GetArgument(std::string& value,
329 const std::string& key)
330 {
331 std::map<std::string, std::string>::const_iterator found = arguments_.find(key);
332
333 if (found == arguments_.end())
334 {
335 return false;
336 }
337 else
338 {
339 value = found->second;
340 return true;
341 }
342 }
343
344
345 extern "C"
346 {
347 int main(int argc, char const *argv[])
348 {
349 OrthancStone::StoneInitialize();
350 Orthanc::Logging::EnableInfoLevel(true);
351 // Orthanc::Logging::EnableTraceLevel(true);
352 EM_ASM(window.dispatchEvent(new CustomEvent("WebAssemblyLoaded")););
353 }
354
355 EMSCRIPTEN_KEEPALIVE
356 void SetArgument(const char* key, const char* value)
357 {
358 // This is called for each GET argument (cf. "app.js")
359 LOG(INFO) << "Received GET argument: [" << key << "] = [" << value << "]";
360 arguments_[key] = value;
361 }
362
363 EMSCRIPTEN_KEEPALIVE
364 void Initialize()
365 {
366 try
367 {
368 oracle_.SetOrthancRoot("..");
369
370 loader_.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(ct_, oracle_, oracle_));
371
372 widget1_.reset(new OrthancStone::VolumeSlicerWidget(broker_, "mycanvas1", OrthancStone::VolumeProjection_Axial));
373 {
374 std::unique_ptr<OrthancStone::GrayscaleStyleConfigurator> style(new OrthancStone::GrayscaleStyleConfigurator);
375 style->SetLinearInterpolation(true);
376 style->SetWindowing(OrthancStone::ImageWindowing_Bone);
377 widget1_->SetSlicer(0, loader_, *loader_, style.release());
378 }
379 widget1_->UpdateSize();
380
381 widget2_.reset(new OrthancStone::VolumeSlicerWidget(broker_, "mycanvas2", OrthancStone::VolumeProjection_Coronal));
382 {
383 std::unique_ptr<OrthancStone::GrayscaleStyleConfigurator> style(new OrthancStone::GrayscaleStyleConfigurator);
384 style->SetLinearInterpolation(true);
385 style->SetWindowing(OrthancStone::ImageWindowing_Bone);
386 widget2_->SetSlicer(0, loader_, *loader_, style.release());
387 }
388 widget2_->UpdateSize();
389
390 widget3_.reset(new OrthancStone::VolumeSlicerWidget(broker_, "mycanvas3", OrthancStone::VolumeProjection_Sagittal));
391 {
392 std::unique_ptr<OrthancStone::GrayscaleStyleConfigurator> style(new OrthancStone::GrayscaleStyleConfigurator);
393 style->SetLinearInterpolation(true);
394 style->SetWindowing(OrthancStone::ImageWindowing_Bone);
395 widget3_->SetSlicer(0, loader_, *loader_, style.release());
396 }
397 widget3_->UpdateSize();
398
399 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, OnWindowResize); // DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 !!
400
401 emscripten_set_wheel_callback("#mycanvas1", widget1_.get(), false, OnMouseWheel);
402 emscripten_set_wheel_callback("#mycanvas2", widget2_.get(), false, OnMouseWheel);
403 emscripten_set_wheel_callback("#mycanvas3", widget3_.get(), false, OnMouseWheel);
404
405 emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, OnKeyDown);
406 emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, OnKeyUp);
407
408 emscripten_request_animation_frame_loop(OnAnimationFrame, NULL);
409
410
411 std::string ct;
412 if (GetArgument(ct, "ct"))
413 {
414 //loader_->LoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa");
415 loader_->LoadSeries(ct);
416 }
417 else
418 {
419 LOG(ERROR) << "No Orthanc identifier for the CT series was provided";
420 }
421 }
422 catch (Orthanc::OrthancException& e)
423 {
424 LOG(ERROR) << "Exception during Initialize(): " << e.What();
425 }
426 }
427 }