Mercurial > hg > orthanc-stone
comparison Resources/Graveyard/Deprecated/Samples/Sdl/Loader.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/Sdl/Loader.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 #include "../../Framework/Loaders/DicomStructureSetLoader.h" | |
23 #include "../../Framework/Loaders/OrthancMultiframeVolumeLoader.h" | |
24 #include "../../Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h" | |
25 #include "../../Framework/Oracle/SleepOracleCommand.h" | |
26 #include "../../Framework/Oracle/ThreadedOracle.h" | |
27 #include "../../Framework/Scene2D/CairoCompositor.h" | |
28 #include "../../Framework/Scene2D/GrayscaleStyleConfigurator.h" | |
29 #include "../../Framework/Scene2D/LookupTableStyleConfigurator.h" | |
30 #include "../../Framework/StoneInitialization.h" | |
31 #include "../../Framework/Volumes/VolumeSceneLayerSource.h" | |
32 #include "../../Framework/Volumes/DicomVolumeImageMPRSlicer.h" | |
33 #include "../../Framework/Volumes/DicomVolumeImageReslicer.h" | |
34 | |
35 // From Orthanc framework | |
36 #include <Core/Images/ImageProcessing.h> | |
37 #include <Core/Images/PngWriter.h> | |
38 #include <Core/Logging.h> | |
39 #include <Core/OrthancException.h> | |
40 #include <Core/SystemToolbox.h> | |
41 | |
42 | |
43 namespace OrthancStone | |
44 { | |
45 class NativeApplicationContext : public IMessageEmitter | |
46 { | |
47 private: | |
48 boost::shared_mutex mutex_; | |
49 MessageBroker broker_; | |
50 IObservable oracleObservable_; | |
51 | |
52 public: | |
53 NativeApplicationContext() : | |
54 oracleObservable_(broker_) | |
55 { | |
56 } | |
57 | |
58 | |
59 virtual void EmitMessage(const IObserver& observer, | |
60 const IMessage& message) ORTHANC_OVERRIDE | |
61 { | |
62 try | |
63 { | |
64 boost::unique_lock<boost::shared_mutex> lock(mutex_); | |
65 oracleObservable_.EmitMessage(observer, message); | |
66 } | |
67 catch (Orthanc::OrthancException& e) | |
68 { | |
69 LOG(ERROR) << "Exception while emitting a message: " << e.What(); | |
70 } | |
71 } | |
72 | |
73 | |
74 class ReaderLock : public boost::noncopyable | |
75 { | |
76 private: | |
77 NativeApplicationContext& that_; | |
78 boost::shared_lock<boost::shared_mutex> lock_; | |
79 | |
80 public: | |
81 ReaderLock(NativeApplicationContext& that) : | |
82 that_(that), | |
83 lock_(that.mutex_) | |
84 { | |
85 } | |
86 }; | |
87 | |
88 | |
89 class WriterLock : public boost::noncopyable | |
90 { | |
91 private: | |
92 NativeApplicationContext& that_; | |
93 boost::unique_lock<boost::shared_mutex> lock_; | |
94 | |
95 public: | |
96 WriterLock(NativeApplicationContext& that) : | |
97 that_(that), | |
98 lock_(that.mutex_) | |
99 { | |
100 } | |
101 | |
102 MessageBroker& GetBroker() | |
103 { | |
104 return that_.broker_; | |
105 } | |
106 | |
107 IObservable& GetOracleObservable() | |
108 { | |
109 return that_.oracleObservable_; | |
110 } | |
111 }; | |
112 }; | |
113 } | |
114 | |
115 | |
116 | |
117 class Toto : public OrthancStone::IObserver | |
118 { | |
119 private: | |
120 OrthancStone::CoordinateSystem3D plane_; | |
121 OrthancStone::IOracle& oracle_; | |
122 OrthancStone::Scene2D scene_; | |
123 std::unique_ptr<OrthancStone::VolumeSceneLayerSource> source1_, source2_, source3_; | |
124 | |
125 | |
126 void Refresh() | |
127 { | |
128 if (source1_.get() != NULL) | |
129 { | |
130 source1_->Update(plane_); | |
131 } | |
132 | |
133 if (source2_.get() != NULL) | |
134 { | |
135 source2_->Update(plane_); | |
136 } | |
137 | |
138 if (source3_.get() != NULL) | |
139 { | |
140 source3_->Update(plane_); | |
141 } | |
142 | |
143 scene_.FitContent(1024, 768); | |
144 | |
145 { | |
146 OrthancStone::CairoCompositor compositor(scene_, 1024, 768); | |
147 compositor.Refresh(); | |
148 | |
149 Orthanc::ImageAccessor accessor; | |
150 compositor.GetCanvas().GetReadOnlyAccessor(accessor); | |
151 | |
152 Orthanc::Image tmp(Orthanc::PixelFormat_RGB24, accessor.GetWidth(), accessor.GetHeight(), false); | |
153 Orthanc::ImageProcessing::Convert(tmp, accessor); | |
154 | |
155 static unsigned int count = 0; | |
156 char buf[64]; | |
157 sprintf(buf, "scene-%06d.png", count++); | |
158 | |
159 Orthanc::PngWriter writer; | |
160 writer.WriteToFile(buf, tmp); | |
161 } | |
162 } | |
163 | |
164 | |
165 void Handle(const OrthancStone::DicomVolumeImage::GeometryReadyMessage& message) | |
166 { | |
167 printf("Geometry ready\n"); | |
168 | |
169 plane_ = message.GetOrigin().GetGeometry().GetSagittalGeometry(); | |
170 //plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry(); | |
171 //plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry(); | |
172 plane_.SetOrigin(message.GetOrigin().GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f)); | |
173 | |
174 Refresh(); | |
175 } | |
176 | |
177 | |
178 void Handle(const OrthancStone::SleepOracleCommand::TimeoutMessage& message) | |
179 { | |
180 if (message.GetOrigin().HasPayload()) | |
181 { | |
182 printf("TIMEOUT! %d\n", dynamic_cast<const Orthanc::SingleValueObject<unsigned int>& >(message.GetOrigin().GetPayload()).GetValue()); | |
183 } | |
184 else | |
185 { | |
186 printf("TIMEOUT\n"); | |
187 | |
188 Refresh(); | |
189 | |
190 /** | |
191 * The sleep() leads to a crash if the oracle is still running, | |
192 * while this object is destroyed. Always stop the oracle before | |
193 * destroying active objects. (*) | |
194 **/ | |
195 // boost::this_thread::sleep(boost::posix_time::seconds(2)); | |
196 | |
197 oracle_.Schedule(*this, new OrthancStone::SleepOracleCommand(message.GetOrigin().GetDelay())); | |
198 } | |
199 } | |
200 | |
201 void Handle(const OrthancStone::OrthancRestApiCommand::SuccessMessage& message) | |
202 { | |
203 Json::Value v; | |
204 message.ParseJsonBody(v); | |
205 | |
206 printf("ICI [%s]\n", v.toStyledString().c_str()); | |
207 } | |
208 | |
209 void Handle(const OrthancStone::GetOrthancImageCommand::SuccessMessage& message) | |
210 { | |
211 printf("IMAGE %dx%d\n", message.GetImage().GetWidth(), message.GetImage().GetHeight()); | |
212 } | |
213 | |
214 void Handle(const OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage& message) | |
215 { | |
216 printf("WebViewer %dx%d\n", message.GetImage().GetWidth(), message.GetImage().GetHeight()); | |
217 } | |
218 | |
219 void Handle(const OrthancStone::OracleCommandExceptionMessage& message) | |
220 { | |
221 printf("EXCEPTION: [%s] on command type %d\n", message.GetException().What(), message.GetCommand().GetType()); | |
222 | |
223 switch (message.GetCommand().GetType()) | |
224 { | |
225 case OrthancStone::IOracleCommand::Type_GetOrthancWebViewerJpeg: | |
226 printf("URI: [%s]\n", dynamic_cast<const OrthancStone::GetOrthancWebViewerJpegCommand&> | |
227 (message.GetCommand()).GetUri().c_str()); | |
228 break; | |
229 | |
230 default: | |
231 break; | |
232 } | |
233 } | |
234 | |
235 public: | |
236 Toto(OrthancStone::IOracle& oracle, | |
237 OrthancStone::IObservable& oracleObservable) : | |
238 IObserver(oracleObservable.GetBroker()), | |
239 oracle_(oracle) | |
240 { | |
241 oracleObservable.RegisterObserverCallback | |
242 (new OrthancStone::Callable | |
243 <Toto, OrthancStone::SleepOracleCommand::TimeoutMessage>(*this, &Toto::Handle)); | |
244 | |
245 oracleObservable.RegisterObserverCallback | |
246 (new OrthancStone::Callable | |
247 <Toto, OrthancStone::OrthancRestApiCommand::SuccessMessage>(*this, &Toto::Handle)); | |
248 | |
249 oracleObservable.RegisterObserverCallback | |
250 (new OrthancStone::Callable | |
251 <Toto, OrthancStone::GetOrthancImageCommand::SuccessMessage>(*this, &Toto::Handle)); | |
252 | |
253 oracleObservable.RegisterObserverCallback | |
254 (new OrthancStone::Callable | |
255 <Toto, OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage>(*this, &Toto::Handle)); | |
256 | |
257 oracleObservable.RegisterObserverCallback | |
258 (new OrthancStone::Callable | |
259 <Toto, OrthancStone::OracleCommandExceptionMessage>(*this, &Toto::Handle)); | |
260 } | |
261 | |
262 void SetReferenceLoader(OrthancStone::IObservable& loader) | |
263 { | |
264 loader.RegisterObserverCallback | |
265 (new OrthancStone::Callable | |
266 <Toto, OrthancStone::DicomVolumeImage::GeometryReadyMessage>(*this, &Toto::Handle)); | |
267 } | |
268 | |
269 void SetVolume1(int depth, | |
270 const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume, | |
271 OrthancStone::ILayerStyleConfigurator* style) | |
272 { | |
273 source1_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume)); | |
274 | |
275 if (style != NULL) | |
276 { | |
277 source1_->SetConfigurator(style); | |
278 } | |
279 } | |
280 | |
281 void SetVolume2(int depth, | |
282 const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume, | |
283 OrthancStone::ILayerStyleConfigurator* style) | |
284 { | |
285 source2_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume)); | |
286 | |
287 if (style != NULL) | |
288 { | |
289 source2_->SetConfigurator(style); | |
290 } | |
291 } | |
292 | |
293 void SetStructureSet(int depth, | |
294 const boost::shared_ptr<OrthancStone::DicomStructureSetLoader>& volume) | |
295 { | |
296 source3_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume)); | |
297 } | |
298 | |
299 }; | |
300 | |
301 | |
302 void Run(OrthancStone::NativeApplicationContext& context, | |
303 OrthancStone::ThreadedOracle& oracle) | |
304 { | |
305 // the oracle has been supplied with the context (as an IEmitter) upon | |
306 // creation | |
307 boost::shared_ptr<OrthancStone::DicomVolumeImage> ct(new OrthancStone::DicomVolumeImage); | |
308 boost::shared_ptr<OrthancStone::DicomVolumeImage> dose(new OrthancStone::DicomVolumeImage); | |
309 | |
310 | |
311 boost::shared_ptr<Toto> toto; | |
312 boost::shared_ptr<OrthancStone::OrthancSeriesVolumeProgressiveLoader> ctLoader; | |
313 boost::shared_ptr<OrthancStone::OrthancMultiframeVolumeLoader> doseLoader; | |
314 boost::shared_ptr<OrthancStone::DicomStructureSetLoader> rtstructLoader; | |
315 | |
316 { | |
317 OrthancStone::NativeApplicationContext::WriterLock lock(context); | |
318 toto.reset(new Toto(oracle, lock.GetOracleObservable())); | |
319 | |
320 // the oracle is used to schedule commands | |
321 // the oracleObservable is used by the loaders to: | |
322 // - request the broker (lifetime mgmt) | |
323 // - register the loader callbacks (called indirectly by the oracle) | |
324 ctLoader.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(ct, oracle, lock.GetOracleObservable())); | |
325 doseLoader.reset(new OrthancStone::OrthancMultiframeVolumeLoader(dose, oracle, lock.GetOracleObservable())); | |
326 rtstructLoader.reset(new OrthancStone::DicomStructureSetLoader(oracle, lock.GetOracleObservable())); | |
327 } | |
328 | |
329 | |
330 //toto->SetReferenceLoader(*ctLoader); | |
331 toto->SetReferenceLoader(*doseLoader); | |
332 | |
333 | |
334 #if 1 | |
335 toto->SetVolume1(0, ctLoader, new OrthancStone::GrayscaleStyleConfigurator); | |
336 #else | |
337 { | |
338 boost::shared_ptr<OrthancStone::IVolumeSlicer> reslicer(new OrthancStone::DicomVolumeImageReslicer(ct)); | |
339 toto->SetVolume1(0, reslicer, new OrthancStone::GrayscaleStyleConfigurator); | |
340 } | |
341 #endif | |
342 | |
343 | |
344 { | |
345 std::unique_ptr<OrthancStone::LookupTableStyleConfigurator> config(new OrthancStone::LookupTableStyleConfigurator); | |
346 config->SetLookupTable(Orthanc::EmbeddedResources::COLORMAP_HOT); | |
347 | |
348 boost::shared_ptr<OrthancStone::DicomVolumeImageMPRSlicer> tmp(new OrthancStone::DicomVolumeImageMPRSlicer(dose)); | |
349 toto->SetVolume2(1, tmp, config.release()); | |
350 } | |
351 | |
352 toto->SetStructureSet(2, rtstructLoader); | |
353 | |
354 oracle.Schedule(*toto, new OrthancStone::SleepOracleCommand(100)); | |
355 | |
356 if (0) | |
357 { | |
358 Json::Value v = Json::objectValue; | |
359 v["Level"] = "Series"; | |
360 v["Query"] = Json::objectValue; | |
361 | |
362 std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand); | |
363 command->SetMethod(Orthanc::HttpMethod_Post); | |
364 command->SetUri("/tools/find"); | |
365 command->SetBody(v); | |
366 | |
367 oracle.Schedule(*toto, command.release()); | |
368 } | |
369 | |
370 if(0) | |
371 { | |
372 if (0) | |
373 { | |
374 std::unique_ptr<OrthancStone::GetOrthancImageCommand> command(new OrthancStone::GetOrthancImageCommand); | |
375 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Jpeg))); | |
376 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/preview"); | |
377 oracle.Schedule(*toto, command.release()); | |
378 } | |
379 | |
380 if (0) | |
381 { | |
382 std::unique_ptr<OrthancStone::GetOrthancImageCommand> command(new OrthancStone::GetOrthancImageCommand); | |
383 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Png))); | |
384 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/preview"); | |
385 oracle.Schedule(*toto, command.release()); | |
386 } | |
387 | |
388 if (0) | |
389 { | |
390 std::unique_ptr<OrthancStone::GetOrthancImageCommand> command(new OrthancStone::GetOrthancImageCommand); | |
391 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Png))); | |
392 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/image-uint16"); | |
393 oracle.Schedule(*toto, command.release()); | |
394 } | |
395 | |
396 if (0) | |
397 { | |
398 std::unique_ptr<OrthancStone::GetOrthancImageCommand> command(new OrthancStone::GetOrthancImageCommand); | |
399 command->SetHttpHeader("Accept-Encoding", "gzip"); | |
400 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam))); | |
401 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/image-uint16"); | |
402 oracle.Schedule(*toto, command.release()); | |
403 } | |
404 | |
405 if (0) | |
406 { | |
407 std::unique_ptr<OrthancStone::GetOrthancImageCommand> command(new OrthancStone::GetOrthancImageCommand); | |
408 command->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam))); | |
409 command->SetUri("/instances/6687cc73-07cae193-52ff29c8-f646cb16-0753ed92/image-uint16"); | |
410 oracle.Schedule(*toto, command.release()); | |
411 } | |
412 | |
413 if (0) | |
414 { | |
415 std::unique_ptr<OrthancStone::GetOrthancWebViewerJpegCommand> command(new OrthancStone::GetOrthancWebViewerJpegCommand); | |
416 command->SetHttpHeader("Accept-Encoding", "gzip"); | |
417 command->SetInstance("e6c7c20b-c9f65d7e-0d76f2e2-830186f2-3e3c600e"); | |
418 command->SetQuality(90); | |
419 oracle.Schedule(*toto, command.release()); | |
420 } | |
421 | |
422 | |
423 if (0) | |
424 { | |
425 for (unsigned int i = 0; i < 10; i++) | |
426 { | |
427 std::unique_ptr<OrthancStone::SleepOracleCommand> command(new OrthancStone::SleepOracleCommand(i * 1000)); | |
428 command->SetPayload(new Orthanc::SingleValueObject<unsigned int>(42 * i)); | |
429 oracle.Schedule(*toto, command.release()); | |
430 } | |
431 } | |
432 } | |
433 | |
434 // 2017-11-17-Anonymized | |
435 #if 0 | |
436 // BGO data | |
437 ctLoader->LoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // CT | |
438 doseLoader->LoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // RT-DOSE | |
439 //rtstructLoader->LoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"); // RT-STRUCT | |
440 #else | |
441 //ctLoader->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT | |
442 //doseLoader->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE | |
443 //rtstructLoader->LoadInstance("83d9c0c3-913a7fee-610097d7-cbf0522d-fd75bee6"); // RT-STRUCT | |
444 | |
445 // 2017-05-16 | |
446 ctLoader->LoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // CT | |
447 doseLoader->LoadInstance("eac822ef-a395f94e-e8121fe0-8411fef8-1f7bffad"); // RT-DOSE | |
448 rtstructLoader->LoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"); // RT-STRUCT | |
449 #endif | |
450 // 2015-01-28-Multiframe | |
451 //doseLoader->LoadInstance("88f71e2a-5fad1c61-96ed14d6-5b3d3cf7-a5825279"); // Multiframe CT | |
452 | |
453 // Delphine | |
454 //ctLoader->LoadSeries("5990e39c-51e5f201-fe87a54c-31a55943-e59ef80e"); // CT | |
455 //ctLoader->LoadSeries("67f1b334-02c16752-45026e40-a5b60b6b-030ecab5"); // Lung 1/10mm | |
456 | |
457 | |
458 { | |
459 LOG(WARNING) << "...Waiting for Ctrl-C..."; | |
460 | |
461 oracle.Start(); | |
462 | |
463 Orthanc::SystemToolbox::ServerBarrier(); | |
464 | |
465 /** | |
466 * WARNING => The oracle must be stopped BEFORE the objects using | |
467 * it are destroyed!!! This forces to wait for the completion of | |
468 * the running callback methods. Otherwise, the callbacks methods | |
469 * might still be running while their parent object is destroyed, | |
470 * resulting in crashes. This is very visible if adding a sleep(), | |
471 * as in (*). | |
472 **/ | |
473 | |
474 oracle.Stop(); | |
475 } | |
476 } | |
477 | |
478 | |
479 | |
480 /** | |
481 * IMPORTANT: The full arguments to "main()" are needed for SDL on | |
482 * Windows. Otherwise, one gets the linking error "undefined reference | |
483 * to `SDL_main'". https://wiki.libsdl.org/FAQWindows | |
484 **/ | |
485 int main(int argc, char* argv[]) | |
486 { | |
487 OrthancStone::StoneInitialize(); | |
488 //Orthanc::Logging::EnableInfoLevel(true); | |
489 | |
490 try | |
491 { | |
492 OrthancStone::NativeApplicationContext context; | |
493 | |
494 OrthancStone::ThreadedOracle oracle(context); | |
495 //oracle.SetThreadsCount(1); | |
496 | |
497 { | |
498 Orthanc::WebServiceParameters p; | |
499 //p.SetUrl("http://localhost:8043/"); | |
500 p.SetCredentials("orthanc", "orthanc"); | |
501 oracle.SetOrthancParameters(p); | |
502 } | |
503 | |
504 //oracle.Start(); | |
505 | |
506 Run(context, oracle); | |
507 | |
508 //oracle.Stop(); | |
509 } | |
510 catch (Orthanc::OrthancException& e) | |
511 { | |
512 LOG(ERROR) << "EXCEPTION: " << e.What(); | |
513 } | |
514 | |
515 OrthancStone::StoneFinalize(); | |
516 | |
517 return 0; | |
518 } |