comparison Deprecated/Samples/Sdl/FusionMprSdl.cpp @ 1402:65e1e4b08302

moved deprecated samples into Deprecated
author Alain Mazy <alain@mazy.be>
date Wed, 29 Apr 2020 20:50:53 +0200
parents Samples/Deprecated/Sdl/FusionMprSdl.cpp@eac254fb6791
children
comparison
equal deleted inserted replaced
1401:f6a2d46d2b76 1402:65e1e4b08302
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 #include "FusionMprSdl.h"
22
23 #include "../../Framework/OpenGL/SdlOpenGLContext.h"
24
25 #include "../../Framework/StoneInitialization.h"
26
27 #include "../../Framework/Scene2D/CairoCompositor.h"
28 #include "../../Framework/Scene2D/ColorTextureSceneLayer.h"
29 #include "../../Framework/Scene2D/OpenGLCompositor.h"
30 #include "../../Framework/Scene2D/PanSceneTracker.h"
31 #include "../../Framework/Scene2D/ZoomSceneTracker.h"
32 #include "../../Framework/Scene2D/RotateSceneTracker.h"
33
34 #include "../../Framework/Scene2DViewport/UndoStack.h"
35 #include "../../Framework/Scene2DViewport/CreateLineMeasureTracker.h"
36 #include "../../Framework/Scene2DViewport/CreateAngleMeasureTracker.h"
37 #include "../../Framework/Scene2DViewport/IFlexiblePointerTracker.h"
38 #include "../../Framework/Scene2DViewport/MeasureTool.h"
39 #include "../../Framework/Scene2DViewport/PredeclaredTypes.h"
40
41 #include "../../Framework/Volumes/VolumeSceneLayerSource.h"
42
43 #include <Core/Images/Image.h>
44 #include <Core/Images/ImageProcessing.h>
45 #include <Core/Images/PngWriter.h>
46 #include <Core/Logging.h>
47 #include <Core/OrthancException.h>
48
49 #include <boost/shared_ptr.hpp>
50 #include <boost/weak_ptr.hpp>
51 #include <boost/make_shared.hpp>
52
53 #include <stdio.h>
54 #include "../../Framework/Oracle/GetOrthancWebViewerJpegCommand.h"
55 #include "../../Framework/Oracle/ThreadedOracle.h"
56 #include "../../Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h"
57 #include "../../Framework/Loaders/OrthancMultiframeVolumeLoader.h"
58 #include "../../Framework/Loaders/DicomStructureSetLoader.h"
59 #include "../../Framework/Scene2D/GrayscaleStyleConfigurator.h"
60 #include "../../Framework/Scene2D/LookupTableStyleConfigurator.h"
61 #include "../../Framework/Volumes/DicomVolumeImageMPRSlicer.h"
62 #include "Core/SystemToolbox.h"
63
64 namespace OrthancStone
65 {
66 const char* FusionMprMeasureToolToString(size_t i)
67 {
68 static const char* descs[] = {
69 "FusionMprGuiTool_Rotate",
70 "FusionMprGuiTool_Pan",
71 "FusionMprGuiTool_Zoom",
72 "FusionMprGuiTool_LineMeasure",
73 "FusionMprGuiTool_CircleMeasure",
74 "FusionMprGuiTool_AngleMeasure",
75 "FusionMprGuiTool_EllipseMeasure",
76 "FusionMprGuiTool_LAST"
77 };
78 if (i >= FusionMprGuiTool_LAST)
79 {
80 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Wrong tool index");
81 }
82 return descs[i];
83 }
84
85 Scene2D& FusionMprSdlApp::GetScene()
86 {
87 return controller_->GetScene();
88 }
89
90 const Scene2D& FusionMprSdlApp::GetScene() const
91 {
92 return controller_->GetScene();
93 }
94
95 void FusionMprSdlApp::SelectNextTool()
96 {
97 currentTool_ = static_cast<FusionMprGuiTool>(currentTool_ + 1);
98 if (currentTool_ == FusionMprGuiTool_LAST)
99 currentTool_ = static_cast<FusionMprGuiTool>(0);;
100 printf("Current tool is now: %s\n", FusionMprMeasureToolToString(currentTool_));
101 }
102
103 void FusionMprSdlApp::DisplayInfoText()
104 {
105 // do not try to use stuff too early!
106 ICompositor* pCompositor = &(viewport_.GetCompositor());
107 if (pCompositor == NULL)
108 return;
109
110 std::stringstream msg;
111
112 for (std::map<std::string, std::string>::const_iterator kv = infoTextMap_.begin();
113 kv != infoTextMap_.end(); ++kv)
114 {
115 msg << kv->first << " : " << kv->second << std::endl;
116 }
117 std::string msgS = msg.str();
118
119 TextSceneLayer* layerP = NULL;
120 if (GetScene().HasLayer(FIXED_INFOTEXT_LAYER_ZINDEX))
121 {
122 TextSceneLayer& layer = dynamic_cast<TextSceneLayer&>(
123 GetScene().GetLayer(FIXED_INFOTEXT_LAYER_ZINDEX));
124 layerP = &layer;
125 }
126 else
127 {
128 std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
129 layerP = layer.get();
130 layer->SetColor(0, 255, 0);
131 layer->SetFontIndex(1);
132 layer->SetBorder(20);
133 layer->SetAnchor(BitmapAnchor_TopLeft);
134 //layer->SetPosition(0,0);
135 GetScene().SetLayer(FIXED_INFOTEXT_LAYER_ZINDEX, layer.release());
136 }
137 // position the fixed info text in the upper right corner
138 layerP->SetText(msgS.c_str());
139 double cX = viewport_.GetCompositor().GetCanvasWidth() * (-0.5);
140 double cY = viewport_.GetCompositor().GetCanvasHeight() * (-0.5);
141 GetScene().GetCanvasToSceneTransform().Apply(cX,cY);
142 layerP->SetPosition(cX, cY);
143 }
144
145 void FusionMprSdlApp::DisplayFloatingCtrlInfoText(const PointerEvent& e)
146 {
147 ScenePoint2D p = e.GetMainPosition().Apply(GetScene().GetCanvasToSceneTransform());
148
149 char buf[128];
150 sprintf(buf, "S:(%0.02f,%0.02f) C:(%0.02f,%0.02f)",
151 p.GetX(), p.GetY(),
152 e.GetMainPosition().GetX(), e.GetMainPosition().GetY());
153
154 if (GetScene().HasLayer(FLOATING_INFOTEXT_LAYER_ZINDEX))
155 {
156 TextSceneLayer& layer =
157 dynamic_cast<TextSceneLayer&>(GetScene().GetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX));
158 layer.SetText(buf);
159 layer.SetPosition(p.GetX(), p.GetY());
160 }
161 else
162 {
163 std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
164 layer->SetColor(0, 255, 0);
165 layer->SetText(buf);
166 layer->SetBorder(20);
167 layer->SetAnchor(BitmapAnchor_BottomCenter);
168 layer->SetPosition(p.GetX(), p.GetY());
169 GetScene().SetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX, layer.release());
170 }
171 }
172
173 void FusionMprSdlApp::HideInfoText()
174 {
175 GetScene().DeleteLayer(FLOATING_INFOTEXT_LAYER_ZINDEX);
176 }
177
178 void FusionMprSdlApp::HandleApplicationEvent(
179 const SDL_Event & event)
180 {
181 DisplayInfoText();
182
183 if (event.type == SDL_MOUSEMOTION)
184 {
185 int scancodeCount = 0;
186 const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount);
187
188 if (activeTracker_.get() == NULL &&
189 SDL_SCANCODE_LALT < scancodeCount &&
190 keyboardState[SDL_SCANCODE_LALT])
191 {
192 // The "left-ctrl" key is down, while no tracker is present
193 // Let's display the info text
194 PointerEvent e;
195 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates(
196 event.button.x, event.button.y));
197
198 DisplayFloatingCtrlInfoText(e);
199 }
200 else
201 {
202 HideInfoText();
203 //LOG(TRACE) << "(event.type == SDL_MOUSEMOTION)";
204 if (activeTracker_.get() != NULL)
205 {
206 //LOG(TRACE) << "(activeTracker_.get() != NULL)";
207 PointerEvent e;
208 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates(
209 event.button.x, event.button.y));
210
211 //LOG(TRACE) << "event.button.x = " << event.button.x << " " <<
212 // "event.button.y = " << event.button.y;
213 LOG(TRACE) << "activeTracker_->PointerMove(e); " <<
214 e.GetMainPosition().GetX() << " " << e.GetMainPosition().GetY();
215
216 activeTracker_->PointerMove(e);
217 if (!activeTracker_->IsAlive())
218 activeTracker_.reset();
219 }
220 }
221 }
222 else if (event.type == SDL_MOUSEBUTTONUP)
223 {
224 if (activeTracker_)
225 {
226 PointerEvent e;
227 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates(event.button.x, event.button.y));
228 activeTracker_->PointerUp(e);
229 if (!activeTracker_->IsAlive())
230 activeTracker_.reset();
231 }
232 }
233 else if (event.type == SDL_MOUSEBUTTONDOWN)
234 {
235 PointerEvent e;
236 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates(
237 event.button.x, event.button.y));
238 if (activeTracker_)
239 {
240 activeTracker_->PointerDown(e);
241 if (!activeTracker_->IsAlive())
242 activeTracker_.reset();
243 }
244 else
245 {
246 // we ATTEMPT to create a tracker if need be
247 activeTracker_ = CreateSuitableTracker(event, e);
248 }
249 }
250 else if (event.type == SDL_KEYDOWN &&
251 event.key.repeat == 0 /* Ignore key bounce */)
252 {
253 switch (event.key.keysym.sym)
254 {
255 case SDLK_ESCAPE:
256 if (activeTracker_)
257 {
258 activeTracker_->Cancel();
259 if (!activeTracker_->IsAlive())
260 activeTracker_.reset();
261 }
262 break;
263
264 case SDLK_t:
265 if (!activeTracker_)
266 SelectNextTool();
267 else
268 {
269 LOG(WARNING) << "You cannot change the active tool when an interaction"
270 " is taking place";
271 }
272 break;
273 case SDLK_s:
274 controller_->FitContent(viewport_.GetCompositor().GetCanvasWidth(),
275 viewport_.GetCompositor().GetCanvasHeight());
276 break;
277
278 case SDLK_z:
279 LOG(TRACE) << "SDLK_z has been pressed. event.key.keysym.mod == " << event.key.keysym.mod;
280 if (event.key.keysym.mod & KMOD_CTRL)
281 {
282 if (controller_->CanUndo())
283 {
284 LOG(TRACE) << "Undoing...";
285 controller_->Undo();
286 }
287 else
288 {
289 LOG(WARNING) << "Nothing to undo!!!";
290 }
291 }
292 break;
293
294 case SDLK_y:
295 LOG(TRACE) << "SDLK_y has been pressed. event.key.keysym.mod == " << event.key.keysym.mod;
296 if (event.key.keysym.mod & KMOD_CTRL)
297 {
298 if (controller_->CanRedo())
299 {
300 LOG(TRACE) << "Redoing...";
301 controller_->Redo();
302 }
303 else
304 {
305 LOG(WARNING) << "Nothing to redo!!!";
306 }
307 }
308 break;
309
310 case SDLK_c:
311 TakeScreenshot(
312 "screenshot.png",
313 viewport_.GetCompositor().GetCanvasWidth(),
314 viewport_.GetCompositor().GetCanvasHeight());
315 break;
316
317 default:
318 break;
319 }
320 }
321 }
322
323
324 void FusionMprSdlApp::OnSceneTransformChanged(
325 const ViewportController::SceneTransformChanged& message)
326 {
327 DisplayInfoText();
328 }
329
330 boost::shared_ptr<IFlexiblePointerTracker> FusionMprSdlApp::CreateSuitableTracker(
331 const SDL_Event & event,
332 const PointerEvent & e)
333 {
334 using namespace Orthanc;
335
336 switch (event.button.button)
337 {
338 case SDL_BUTTON_MIDDLE:
339 return boost::shared_ptr<IFlexiblePointerTracker>(new PanSceneTracker
340 (controller_, e));
341
342 case SDL_BUTTON_RIGHT:
343 return boost::shared_ptr<IFlexiblePointerTracker>(new ZoomSceneTracker
344 (controller_, e, viewport_.GetCompositor().GetCanvasHeight()));
345
346 case SDL_BUTTON_LEFT:
347 {
348 //LOG(TRACE) << "CreateSuitableTracker: case SDL_BUTTON_LEFT:";
349 // TODO: we need to iterate on the set of measuring tool and perform
350 // a hit test to check if a tracker needs to be created for edition.
351 // Otherwise, depending upon the active tool, we might want to create
352 // a "measuring tool creation" tracker
353
354 // TODO: if there are conflicts, we should prefer a tracker that
355 // pertains to the type of measuring tool currently selected (TBD?)
356 boost::shared_ptr<IFlexiblePointerTracker> hitTestTracker = TrackerHitTest(e);
357
358 if (hitTestTracker != NULL)
359 {
360 //LOG(TRACE) << "hitTestTracker != NULL";
361 return hitTestTracker;
362 }
363 else
364 {
365 switch (currentTool_)
366 {
367 case FusionMprGuiTool_Rotate:
368 //LOG(TRACE) << "Creating RotateSceneTracker";
369 return boost::shared_ptr<IFlexiblePointerTracker>(new RotateSceneTracker(
370 controller_, e));
371 case FusionMprGuiTool_Pan:
372 return boost::shared_ptr<IFlexiblePointerTracker>(new PanSceneTracker(
373 controller_, e));
374 case FusionMprGuiTool_Zoom:
375 return boost::shared_ptr<IFlexiblePointerTracker>(new ZoomSceneTracker(
376 controller_, e, viewport_.GetCompositor().GetCanvasHeight()));
377 //case GuiTool_AngleMeasure:
378 // return new AngleMeasureTracker(GetScene(), e);
379 //case GuiTool_CircleMeasure:
380 // return new CircleMeasureTracker(GetScene(), e);
381 //case GuiTool_EllipseMeasure:
382 // return new EllipseMeasureTracker(GetScene(), e);
383 case FusionMprGuiTool_LineMeasure:
384 return boost::shared_ptr<IFlexiblePointerTracker>(new CreateLineMeasureTracker(
385 IObserver::GetBroker(), controller_, e));
386 case FusionMprGuiTool_AngleMeasure:
387 return boost::shared_ptr<IFlexiblePointerTracker>(new CreateAngleMeasureTracker(
388 IObserver::GetBroker(), controller_, e));
389 case FusionMprGuiTool_CircleMeasure:
390 LOG(ERROR) << "Not implemented yet!";
391 return boost::shared_ptr<IFlexiblePointerTracker>();
392 case FusionMprGuiTool_EllipseMeasure:
393 LOG(ERROR) << "Not implemented yet!";
394 return boost::shared_ptr<IFlexiblePointerTracker>();
395 default:
396 throw OrthancException(ErrorCode_InternalError, "Wrong tool!");
397 }
398 }
399 }
400 default:
401 return boost::shared_ptr<IFlexiblePointerTracker>();
402 }
403 }
404
405
406 FusionMprSdlApp::FusionMprSdlApp(MessageBroker& broker)
407 : IObserver(broker)
408 , broker_(broker)
409 , oracleObservable_(broker)
410 , oracle_(*this)
411 , currentTool_(FusionMprGuiTool_Rotate)
412 , undoStack_(new UndoStack)
413 , viewport_("Hello", 1024, 1024, false) // False means we do NOT let Windows treat this as a legacy application that needs to be scaled
414 {
415 //oracleObservable.RegisterObserverCallback
416 //(new Callable
417 // <FusionMprSdlApp, SleepOracleCommand::TimeoutMessage>(*this, &FusionMprSdlApp::Handle));
418
419 //oracleObservable.RegisterObserverCallback
420 //(new Callable
421 // <Toto, GetOrthancImageCommand::SuccessMessage>(*this, &FusionMprSdlApp::Handle));
422
423 //oracleObservable.RegisterObserverCallback
424 //(new Callable
425 // <FusionMprSdlApp, GetOrthancWebViewerJpegCommand::SuccessMessage>(*this, &ToFusionMprSdlAppto::Handle));
426
427 oracleObservable_.RegisterObserverCallback
428 (new Callable
429 <FusionMprSdlApp, OracleCommandExceptionMessage>(*this, &FusionMprSdlApp::Handle));
430
431 controller_ = boost::shared_ptr<ViewportController>(
432 new ViewportController(undoStack_, broker_, viewport_));
433
434 controller_->RegisterObserverCallback(
435 new Callable<FusionMprSdlApp, ViewportController::SceneTransformChanged>
436 (*this, &FusionMprSdlApp::OnSceneTransformChanged));
437
438 TEXTURE_2x2_1_ZINDEX = 1;
439 TEXTURE_1x1_ZINDEX = 2;
440 TEXTURE_2x2_2_ZINDEX = 3;
441 LINESET_1_ZINDEX = 4;
442 LINESET_2_ZINDEX = 5;
443 FLOATING_INFOTEXT_LAYER_ZINDEX = 6;
444 FIXED_INFOTEXT_LAYER_ZINDEX = 7;
445 }
446
447 void FusionMprSdlApp::PrepareScene()
448 {
449 // Texture of 2x2 size
450 {
451 Orthanc::Image i(Orthanc::PixelFormat_RGB24, 2, 2, false);
452
453 uint8_t* p = reinterpret_cast<uint8_t*>(i.GetRow(0));
454 p[0] = 255;
455 p[1] = 0;
456 p[2] = 0;
457
458 p[3] = 0;
459 p[4] = 255;
460 p[5] = 0;
461
462 p = reinterpret_cast<uint8_t*>(i.GetRow(1));
463 p[0] = 0;
464 p[1] = 0;
465 p[2] = 255;
466
467 p[3] = 255;
468 p[4] = 0;
469 p[5] = 0;
470
471 GetScene().SetLayer(TEXTURE_2x2_1_ZINDEX, new ColorTextureSceneLayer(i));
472 }
473 }
474
475 void FusionMprSdlApp::DisableTracker()
476 {
477 if (activeTracker_)
478 {
479 activeTracker_->Cancel();
480 activeTracker_.reset();
481 }
482 }
483
484 void FusionMprSdlApp::TakeScreenshot(const std::string& target,
485 unsigned int canvasWidth,
486 unsigned int canvasHeight)
487 {
488 CairoCompositor compositor(GetScene(), canvasWidth, canvasHeight);
489 compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, FONT_SIZE_0, Orthanc::Encoding_Latin1);
490 compositor.Refresh();
491
492 Orthanc::ImageAccessor canvas;
493 compositor.GetCanvas().GetReadOnlyAccessor(canvas);
494
495 Orthanc::Image png(Orthanc::PixelFormat_RGB24, canvas.GetWidth(), canvas.GetHeight(), false);
496 Orthanc::ImageProcessing::Convert(png, canvas);
497
498 Orthanc::PngWriter writer;
499 writer.WriteToFile(target, png);
500 }
501
502
503 boost::shared_ptr<IFlexiblePointerTracker> FusionMprSdlApp::TrackerHitTest(const PointerEvent & e)
504 {
505 // std::vector<boost::shared_ptr<MeasureTool>> measureTools_;
506 return boost::shared_ptr<IFlexiblePointerTracker>();
507 }
508
509 static void GLAPIENTRY
510 OpenGLMessageCallback(GLenum source,
511 GLenum type,
512 GLuint id,
513 GLenum severity,
514 GLsizei length,
515 const GLchar* message,
516 const void* userParam)
517 {
518 if (severity != GL_DEBUG_SEVERITY_NOTIFICATION)
519 {
520 fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
521 (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
522 type, severity, message);
523 }
524 }
525
526 static bool g_stopApplication = false;
527
528
529 void FusionMprSdlApp::Handle(const DicomVolumeImage::GeometryReadyMessage& message)
530 {
531 printf("Geometry ready\n");
532
533 //plane_ = message.GetOrigin().GetGeometry().GetSagittalGeometry();
534 //plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry();
535 plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry();
536 plane_.SetOrigin(message.GetOrigin().GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f));
537
538 //Refresh();
539 }
540
541
542 void FusionMprSdlApp::Handle(const OracleCommandExceptionMessage& message)
543 {
544 printf("EXCEPTION: [%s] on command type %d\n", message.GetException().What(), message.GetCommand().GetType());
545
546 switch (message.GetCommand().GetType())
547 {
548 case IOracleCommand::Type_GetOrthancWebViewerJpeg:
549 printf("URI: [%s]\n", dynamic_cast<const GetOrthancWebViewerJpegCommand&>
550 (message.GetCommand()).GetUri().c_str());
551 break;
552
553 default:
554 break;
555 }
556 }
557
558 void FusionMprSdlApp::SetVolume1(int depth,
559 const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume,
560 OrthancStone::ILayerStyleConfigurator* style)
561 {
562 source1_.reset(new OrthancStone::VolumeSceneLayerSource(controller_->GetScene(), depth, volume));
563
564 if (style != NULL)
565 {
566 source1_->SetConfigurator(style);
567 }
568 }
569
570 void FusionMprSdlApp::SetVolume2(int depth,
571 const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume,
572 OrthancStone::ILayerStyleConfigurator* style)
573 {
574 source2_.reset(new OrthancStone::VolumeSceneLayerSource(controller_->GetScene(), depth, volume));
575
576 if (style != NULL)
577 {
578 source2_->SetConfigurator(style);
579 }
580 }
581
582 void FusionMprSdlApp::SetStructureSet(int depth,
583 const boost::shared_ptr<OrthancStone::DicomStructureSetLoader>& volume)
584 {
585 source3_.reset(new OrthancStone::VolumeSceneLayerSource(controller_->GetScene(), depth, volume));
586 }
587
588 void FusionMprSdlApp::Run()
589 {
590 // False means we do NOT let Windows treat this as a legacy application
591 // that needs to be scaled
592 controller_->FitContent(viewport_.GetCanvasWidth(), viewport_.GetCanvasHeight());
593
594 glEnable(GL_DEBUG_OUTPUT);
595 glDebugMessageCallback(OpenGLMessageCallback, 0);
596
597 viewport_.GetCompositor().SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT,
598 FONT_SIZE_0, Orthanc::Encoding_Latin1);
599 viewport_.GetCompositor().SetFont(1, Orthanc::EmbeddedResources::UBUNTU_FONT,
600 FONT_SIZE_1, Orthanc::Encoding_Latin1);
601
602
603 //////// from loader
604 {
605 Orthanc::WebServiceParameters p;
606 //p.SetUrl("http://localhost:8043/");
607 p.SetCredentials("orthanc", "orthanc");
608 oracle_.SetOrthancParameters(p);
609 }
610
611 //////// from Run
612
613 boost::shared_ptr<DicomVolumeImage> ct(new DicomVolumeImage);
614 boost::shared_ptr<DicomVolumeImage> dose(new DicomVolumeImage);
615
616
617 boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> ctLoader;
618 boost::shared_ptr<OrthancMultiframeVolumeLoader> doseLoader;
619 boost::shared_ptr<DicomStructureSetLoader> rtstructLoader;
620
621 {
622 ctLoader.reset(new OrthancSeriesVolumeProgressiveLoader(ct, oracle_, oracleObservable_));
623 doseLoader.reset(new OrthancMultiframeVolumeLoader(dose, oracle_, oracleObservable_));
624 rtstructLoader.reset(new DicomStructureSetLoader(oracle_, oracleObservable_));
625 }
626
627 //toto->SetReferenceLoader(*ctLoader);
628 //doseLoader->RegisterObserverCallback
629 //(new Callable
630 // <FusionMprSdlApp, DicomVolumeImage::GeometryReadyMessage>(*this, &FusionMprSdlApp::Handle));
631 ctLoader->RegisterObserverCallback
632 (new Callable
633 <FusionMprSdlApp, DicomVolumeImage::GeometryReadyMessage>(*this, &FusionMprSdlApp::Handle));
634
635 this->SetVolume1(0, ctLoader, new GrayscaleStyleConfigurator);
636
637 {
638 std::unique_ptr<LookupTableStyleConfigurator> config(new LookupTableStyleConfigurator);
639 config->SetLookupTable(Orthanc::EmbeddedResources::COLORMAP_HOT);
640
641 boost::shared_ptr<DicomVolumeImageMPRSlicer> tmp(new DicomVolumeImageMPRSlicer(dose));
642 this->SetVolume2(1, tmp, config.release());
643 }
644
645 this->SetStructureSet(2, rtstructLoader);
646
647 #if 1
648 /*
649 BGO data
650 http://localhost:8042/twiga-orthanc-viewer-demo/twiga-orthanc-viewer-demo.html?ct-series=a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa
651 &
652 dose-instance=830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb
653 &
654 struct-instance=54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9
655 */
656 ctLoader->LoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // CT
657 doseLoader->LoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // RT-DOSE
658 rtstructLoader->LoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"); // RT-STRUCT
659 #else
660 //ctLoader->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT
661 //doseLoader->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE
662 //rtstructLoader->LoadInstance("83d9c0c3-913a7fee-610097d7-cbf0522d-fd75bee6"); // RT-STRUCT
663
664 // 2017-05-16
665 ctLoader->LoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // CT
666 doseLoader->LoadInstance("eac822ef-a395f94e-e8121fe0-8411fef8-1f7bffad"); // RT-DOSE
667 rtstructLoader->LoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"); // RT-STRUCT
668 #endif
669
670 oracle_.Start();
671
672 //// END from loader
673
674 while (!g_stopApplication)
675 {
676 viewport_.GetCompositor().Refresh();
677
678 //////// from loader
679 if (source1_.get() != NULL)
680 {
681 source1_->Update(plane_);
682 }
683
684 if (source2_.get() != NULL)
685 {
686 source2_->Update(plane_);
687 }
688
689 if (source3_.get() != NULL)
690 {
691 source3_->Update(plane_);
692 }
693 //// END from loader
694
695 SDL_Event event;
696 while (!g_stopApplication && SDL_PollEvent(&event))
697 {
698 if (event.type == SDL_QUIT)
699 {
700 g_stopApplication = true;
701 break;
702 }
703 else if (event.type == SDL_WINDOWEVENT &&
704 event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
705 {
706 DisableTracker(); // was: tracker.reset(NULL);
707 }
708 else if (event.type == SDL_KEYDOWN &&
709 event.key.repeat == 0 /* Ignore key bounce */)
710 {
711 switch (event.key.keysym.sym)
712 {
713 case SDLK_f:
714 viewport_.GetWindow().ToggleMaximize();
715 break;
716
717 case SDLK_s:
718 controller_->FitContent(viewport_.GetCanvasWidth(), viewport_.GetCanvasHeight());
719 break;
720
721 case SDLK_q:
722 g_stopApplication = true;
723 break;
724 default:
725 break;
726 }
727 }
728 HandleApplicationEvent(event);
729 }
730 SDL_Delay(1);
731 }
732
733 //// from loader
734
735 //Orthanc::SystemToolbox::ServerBarrier();
736
737 /**
738 * WARNING => The oracle must be stopped BEFORE the objects using
739 * it are destroyed!!! This forces to wait for the completion of
740 * the running callback methods. Otherwise, the callbacks methods
741 * might still be running while their parent object is destroyed,
742 * resulting in crashes. This is very visible if adding a sleep(),
743 * as in (*).
744 **/
745
746 oracle_.Stop();
747 //// END from loader
748 }
749
750 void FusionMprSdlApp::SetInfoDisplayMessage(
751 std::string key, std::string value)
752 {
753 if (value == "")
754 infoTextMap_.erase(key);
755 else
756 infoTextMap_[key] = value;
757 DisplayInfoText();
758 }
759
760 }
761
762
763 boost::weak_ptr<OrthancStone::FusionMprSdlApp> g_app;
764
765 void FusionMprSdl_SetInfoDisplayMessage(std::string key, std::string value)
766 {
767 boost::shared_ptr<OrthancStone::FusionMprSdlApp> app = g_app.lock();
768 if (app)
769 {
770 app->SetInfoDisplayMessage(key, value);
771 }
772 }
773
774 /**
775 * IMPORTANT: The full arguments to "main()" are needed for SDL on
776 * Windows. Otherwise, one gets the linking error "undefined reference
777 * to `SDL_main'". https://wiki.libsdl.org/FAQWindows
778 **/
779 int main(int argc, char* argv[])
780 {
781 using namespace OrthancStone;
782
783 StoneInitialize();
784 Orthanc::Logging::EnableInfoLevel(true);
785 // Orthanc::Logging::EnableTraceLevel(true);
786
787 try
788 {
789 OrthancStone::MessageBroker broker;
790 boost::shared_ptr<FusionMprSdlApp> app(new FusionMprSdlApp(broker));
791 g_app = app;
792 app->PrepareScene();
793 app->Run();
794 }
795 catch (Orthanc::OrthancException& e)
796 {
797 LOG(ERROR) << "EXCEPTION: " << e.What();
798 }
799
800 StoneFinalize();
801
802 return 0;
803 }
804
805