Mercurial > hg > orthanc-stone
comparison Samples/Deprecated/Sdl/FusionMprSdl.cpp @ 1348:eac254fb6791 broker
Moved Application/Samples/* to Application/Samples/Deprecated/* (remaining) + moved Samples/* to Samples/Deprecated/*
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Tue, 07 Apr 2020 14:31:28 +0200 |
parents | Samples/Sdl/FusionMprSdl.cpp@8a0a62189f46 |
children |
comparison
equal
deleted
inserted
replaced
1347:bfd77672d825 | 1348:eac254fb6791 |
---|---|
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 |