comparison Applications/Samples/SingleFrameEditorApplication.h @ 430:b85f635f1eb5 am-vsol-upgrade

added serialization for RadiographyScene
author am@osimis.io
date Thu, 29 Nov 2018 15:11:19 +0100
parents 751fb354149e
children a750f11892ec
comparison
equal deleted inserted replaced
429:c7fb700a7d12 430:b85f635f1eb5
29 #include "../../Framework/Radiography/RadiographyLayerRotateTracker.h" 29 #include "../../Framework/Radiography/RadiographyLayerRotateTracker.h"
30 #include "../../Framework/Radiography/RadiographyScene.h" 30 #include "../../Framework/Radiography/RadiographyScene.h"
31 #include "../../Framework/Radiography/RadiographySceneCommand.h" 31 #include "../../Framework/Radiography/RadiographySceneCommand.h"
32 #include "../../Framework/Radiography/RadiographyWidget.h" 32 #include "../../Framework/Radiography/RadiographyWidget.h"
33 #include "../../Framework/Radiography/RadiographyWindowingTracker.h" 33 #include "../../Framework/Radiography/RadiographyWindowingTracker.h"
34 #include "../../Framework/Radiography/RadiographySceneWriter.h"
35 #include "../../Framework/Radiography/RadiographySceneReader.h"
34 36
35 #include <Core/HttpClient.h> 37 #include <Core/HttpClient.h>
36 #include <Core/Images/FontRegistry.h> 38 #include <Core/Images/FontRegistry.h>
37 #include <Core/Logging.h> 39 #include <Core/Logging.h>
38 #include <Core/OrthancException.h> 40 #include <Core/OrthancException.h>
46 namespace OrthancStone 48 namespace OrthancStone
47 { 49 {
48 namespace Samples 50 namespace Samples
49 { 51 {
50 class RadiographyEditorInteractor : 52 class RadiographyEditorInteractor :
51 public IWorldSceneInteractor, 53 public IWorldSceneInteractor,
52 public IObserver 54 public IObserver
53 { 55 {
54 private: 56 private:
55 enum Tool 57 enum Tool
56 { 58 {
57 Tool_Move, 59 Tool_Move,
58 Tool_Rotate, 60 Tool_Rotate,
59 Tool_Crop, 61 Tool_Crop,
60 Tool_Resize, 62 Tool_Resize,
61 Tool_Windowing 63 Tool_Windowing
62 }; 64 };
63 65
64 66
65 StoneApplicationContext* context_; 67 StoneApplicationContext* context_;
66 UndoRedoStack undoRedoStack_; 68 UndoRedoStack undoRedoStack_;
67 Tool tool_; 69 Tool tool_;
68 70
69 71
70 static double GetHandleSize() 72 static double GetHandleSize()
71 { 73 {
72 return 10.0; 74 return 10.0;
73 } 75 }
74 76
75 77
76 public: 78 public:
77 RadiographyEditorInteractor(MessageBroker& broker) : 79 RadiographyEditorInteractor(MessageBroker& broker) :
78 IObserver(broker), 80 IObserver(broker),
79 context_(NULL), 81 context_(NULL),
80 tool_(Tool_Move) 82 tool_(Tool_Move)
83 85
84 void SetContext(StoneApplicationContext& context) 86 void SetContext(StoneApplicationContext& context)
85 { 87 {
86 context_ = &context; 88 context_ = &context;
87 } 89 }
88 90
89 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& worldWidget, 91 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& worldWidget,
90 const ViewportGeometry& view, 92 const ViewportGeometry& view,
91 MouseButton button, 93 MouseButton button,
92 KeyboardModifiers modifiers, 94 KeyboardModifiers modifiers,
93 int viewportX, 95 int viewportX,
99 RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget); 101 RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget);
100 102
101 if (button == MouseButton_Left) 103 if (button == MouseButton_Left)
102 { 104 {
103 size_t selected; 105 size_t selected;
104 106
105 if (tool_ == Tool_Windowing) 107 if (tool_ == Tool_Windowing)
106 { 108 {
107 return new RadiographyWindowingTracker( 109 return new RadiographyWindowingTracker(
108 undoRedoStack_, widget.GetScene(), 110 undoRedoStack_, widget.GetScene(),
109 viewportX, viewportY, 111 viewportX, viewportY,
110 RadiographyWindowingTracker::Action_DecreaseWidth, 112 RadiographyWindowingTracker::Action_DecreaseWidth,
111 RadiographyWindowingTracker::Action_IncreaseWidth, 113 RadiographyWindowingTracker::Action_IncreaseWidth,
112 RadiographyWindowingTracker::Action_DecreaseCenter, 114 RadiographyWindowingTracker::Action_DecreaseCenter,
113 RadiographyWindowingTracker::Action_IncreaseCenter); 115 RadiographyWindowingTracker::Action_IncreaseCenter);
114 } 116 }
115 else if (!widget.LookupSelectedLayer(selected)) 117 else if (!widget.LookupSelectedLayer(selected))
116 { 118 {
117 // No layer is currently selected 119 // No layer is currently selected
118 size_t layer; 120 size_t layer;
131 Corner corner; 133 Corner corner;
132 if (accessor.GetLayer().LookupCorner(corner, x, y, view.GetZoom(), GetHandleSize())) 134 if (accessor.GetLayer().LookupCorner(corner, x, y, view.GetZoom(), GetHandleSize()))
133 { 135 {
134 switch (tool_) 136 switch (tool_)
135 { 137 {
136 case Tool_Crop: 138 case Tool_Crop:
137 return new RadiographyLayerCropTracker 139 return new RadiographyLayerCropTracker
138 (undoRedoStack_, widget.GetScene(), view, selected, x, y, corner); 140 (undoRedoStack_, widget.GetScene(), view, selected, x, y, corner);
139 141
140 case Tool_Resize: 142 case Tool_Resize:
141 return new RadiographyLayerResizeTracker 143 return new RadiographyLayerResizeTracker
142 (undoRedoStack_, widget.GetScene(), selected, x, y, corner, 144 (undoRedoStack_, widget.GetScene(), selected, x, y, corner,
143 (modifiers & KeyboardModifiers_Shift)); 145 (modifiers & KeyboardModifiers_Shift));
144 146
145 default: 147 default:
146 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 148 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
147 } 149 }
148 } 150 }
149 else 151 else
150 { 152 {
151 size_t layer; 153 size_t layer;
152 154
153 if (widget.GetScene().LookupLayer(layer, x, y)) 155 if (widget.GetScene().LookupLayer(layer, x, y))
154 { 156 {
155 widget.Select(layer); 157 widget.Select(layer);
156 } 158 }
157 else 159 else
158 { 160 {
159 widget.Unselect(); 161 widget.Unselect();
160 } 162 }
161 163
162 return NULL; 164 return NULL;
163 } 165 }
164 } 166 }
165 else 167 else
166 { 168 {
170 { 172 {
171 if (layer == selected) 173 if (layer == selected)
172 { 174 {
173 switch (tool_) 175 switch (tool_)
174 { 176 {
175 case Tool_Move: 177 case Tool_Move:
176 return new RadiographyLayerMoveTracker 178 return new RadiographyLayerMoveTracker
177 (undoRedoStack_, widget.GetScene(), layer, x, y, 179 (undoRedoStack_, widget.GetScene(), layer, x, y,
178 (modifiers & KeyboardModifiers_Shift)); 180 (modifiers & KeyboardModifiers_Shift));
179 181
180 case Tool_Rotate: 182 case Tool_Rotate:
181 return new RadiographyLayerRotateTracker 183 return new RadiographyLayerRotateTracker
182 (undoRedoStack_, widget.GetScene(), view, layer, x, y, 184 (undoRedoStack_, widget.GetScene(), view, layer, x, y,
183 (modifiers & KeyboardModifiers_Shift)); 185 (modifiers & KeyboardModifiers_Shift));
184 186
185 default: 187 default:
186 break; 188 break;
187 } 189 }
188 190
189 return NULL; 191 return NULL;
190 } 192 }
191 else 193 else
230 if (widget.LookupSelectedLayer(selected) && 232 if (widget.LookupSelectedLayer(selected) &&
231 (tool_ == Tool_Crop || 233 (tool_ == Tool_Crop ||
232 tool_ == Tool_Resize)) 234 tool_ == Tool_Resize))
233 { 235 {
234 RadiographyScene::LayerAccessor accessor(widget.GetScene(), selected); 236 RadiographyScene::LayerAccessor accessor(widget.GetScene(), selected);
235 237
236 Corner corner; 238 Corner corner;
237 if (accessor.GetLayer().LookupCorner(corner, x, y, view.GetZoom(), GetHandleSize())) 239 if (accessor.GetLayer().LookupCorner(corner, x, y, view.GetZoom(), GetHandleSize()))
238 { 240 {
239 accessor.GetLayer().GetCorner(x, y, corner); 241 accessor.GetLayer().GetCorner(x, y, corner);
240 242
241 double z = 1.0 / view.GetZoom(); 243 double z = 1.0 / view.GetZoom();
242 244
243 context.SetSourceColor(255, 0, 0); 245 context.SetSourceColor(255, 0, 0);
244 cairo_t* cr = context.GetObject(); 246 cairo_t* cr = context.GetObject();
245 cairo_set_line_width(cr, 2.0 * z); 247 cairo_set_line_width(cr, 2.0 * z);
246 cairo_move_to(cr, x - GetHandleSize() * z, y - GetHandleSize() * z); 248 cairo_move_to(cr, x - GetHandleSize() * z, y - GetHandleSize() * z);
247 cairo_line_to(cr, x + GetHandleSize() * z, y - GetHandleSize() * z); 249 cairo_line_to(cr, x + GetHandleSize() * z, y - GetHandleSize() * z);
268 { 270 {
269 RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget); 271 RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget);
270 272
271 switch (keyChar) 273 switch (keyChar)
272 { 274 {
273 case 'a': 275 case 'a':
274 widget.FitContent(); 276 widget.FitContent();
277 break;
278
279 case 'c':
280 tool_ = Tool_Crop;
281 break;
282
283 case 'd':
284 {
285 // dump to json and reload
286 Json::Value snapshot;
287 RadiographySceneWriter writer;
288 writer.Write(snapshot, widget.GetScene());
289
290 LOG(INFO) << "JSON export was successful: "
291 << snapshot.toStyledString();
292
293 boost::shared_ptr<RadiographyScene> scene(new RadiographyScene(GetBroker()));
294 RadiographySceneReader reader(*scene, context_->GetOrthancApiClient());
295
296 Orthanc::FontRegistry fontRegistry;
297 fontRegistry.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
298
299 reader.SetFontRegistry(fontRegistry);
300 reader.Read(snapshot);
301
302 widget.SetScene(scene);
303 };break;
304
305 case 'e':
306 {
307 Orthanc::DicomMap tags;
308
309 // Minimal set of tags to generate a valid CR image
310 tags.SetValue(Orthanc::DICOM_TAG_ACCESSION_NUMBER, "NOPE", false);
311 tags.SetValue(Orthanc::DICOM_TAG_BODY_PART_EXAMINED, "PELVIS", false);
312 tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "1", false);
313 //tags.SetValue(Orthanc::DICOM_TAG_LATERALITY, "", false);
314 tags.SetValue(Orthanc::DICOM_TAG_MANUFACTURER, "OSIMIS", false);
315 tags.SetValue(Orthanc::DICOM_TAG_MODALITY, "CR", false);
316 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_BIRTH_DATE, "20000101", false);
317 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_ID, "hello", false);
318 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_NAME, "HELLO^WORLD", false);
319 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_ORIENTATION, "", false);
320 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_SEX, "M", false);
321 tags.SetValue(Orthanc::DICOM_TAG_REFERRING_PHYSICIAN_NAME, "HOUSE^MD", false);
322 tags.SetValue(Orthanc::DICOM_TAG_SERIES_NUMBER, "1", false);
323 tags.SetValue(Orthanc::DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.1", false);
324 tags.SetValue(Orthanc::DICOM_TAG_STUDY_ID, "STUDY", false);
325 tags.SetValue(Orthanc::DICOM_TAG_VIEW_POSITION, "", false);
326
327 if (context_ != NULL)
328 {
329 widget.GetScene().ExportDicom(context_->GetOrthancApiClient(),
330 tags, std::string(), 0.1, 0.1, widget.IsInverted(),
331 widget.GetInterpolation(), EXPORT_USING_PAM);
332 }
333
334 break;
335 }
336
337 case 'i':
338 widget.SwitchInvert();
339 break;
340
341 case 'm':
342 tool_ = Tool_Move;
343 break;
344
345 case 'n':
346 {
347 switch (widget.GetInterpolation())
348 {
349 case ImageInterpolation_Nearest:
350 LOG(INFO) << "Switching to bilinear interpolation";
351 widget.SetInterpolation(ImageInterpolation_Bilinear);
275 break; 352 break;
276 353
277 case 'c': 354 case ImageInterpolation_Bilinear:
278 tool_ = Tool_Crop; 355 LOG(INFO) << "Switching to nearest neighbor interpolation";
356 widget.SetInterpolation(ImageInterpolation_Nearest);
279 break; 357 break;
280 358
281 case 'e': 359 default:
282 { 360 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
283 Orthanc::DicomMap tags; 361 }
284
285 // Minimal set of tags to generate a valid CR image
286 tags.SetValue(Orthanc::DICOM_TAG_ACCESSION_NUMBER, "NOPE", false);
287 tags.SetValue(Orthanc::DICOM_TAG_BODY_PART_EXAMINED, "PELVIS", false);
288 tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "1", false);
289 //tags.SetValue(Orthanc::DICOM_TAG_LATERALITY, "", false);
290 tags.SetValue(Orthanc::DICOM_TAG_MANUFACTURER, "OSIMIS", false);
291 tags.SetValue(Orthanc::DICOM_TAG_MODALITY, "CR", false);
292 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_BIRTH_DATE, "20000101", false);
293 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_ID, "hello", false);
294 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_NAME, "HELLO^WORLD", false);
295 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_ORIENTATION, "", false);
296 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_SEX, "M", false);
297 tags.SetValue(Orthanc::DICOM_TAG_REFERRING_PHYSICIAN_NAME, "HOUSE^MD", false);
298 tags.SetValue(Orthanc::DICOM_TAG_SERIES_NUMBER, "1", false);
299 tags.SetValue(Orthanc::DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.1", false);
300 tags.SetValue(Orthanc::DICOM_TAG_STUDY_ID, "STUDY", false);
301 tags.SetValue(Orthanc::DICOM_TAG_VIEW_POSITION, "", false);
302
303 if (context_ != NULL)
304 {
305 widget.GetScene().ExportDicom(context_->GetOrthancApiClient(),
306 tags, std::string(), 0.1, 0.1, widget.IsInverted(),
307 widget.GetInterpolation(), EXPORT_USING_PAM);
308 }
309
310 break;
311 }
312
313 case 'i':
314 widget.SwitchInvert();
315 break;
316
317 case 'm':
318 tool_ = Tool_Move;
319 break;
320
321 case 'n':
322 {
323 switch (widget.GetInterpolation())
324 {
325 case ImageInterpolation_Nearest:
326 LOG(INFO) << "Switching to bilinear interpolation";
327 widget.SetInterpolation(ImageInterpolation_Bilinear);
328 break;
329
330 case ImageInterpolation_Bilinear:
331 LOG(INFO) << "Switching to nearest neighbor interpolation";
332 widget.SetInterpolation(ImageInterpolation_Nearest);
333 break;
334
335 default:
336 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
337 }
338 362
339 break; 363 break;
340 } 364 }
341 365
342 case 'r': 366 case 'r':
343 tool_ = Tool_Rotate; 367 tool_ = Tool_Rotate;
344 break; 368 break;
345 369
346 case 's': 370 case 's':
347 tool_ = Tool_Resize; 371 tool_ = Tool_Resize;
348 break; 372 break;
349 373
350 case 'w': 374 case 'w':
351 tool_ = Tool_Windowing; 375 tool_ = Tool_Windowing;
352 break; 376 break;
353 377
354 case 'y': 378 case 'y':
355 if (modifiers & KeyboardModifiers_Control) 379 if (modifiers & KeyboardModifiers_Control)
356 { 380 {
357 undoRedoStack_.Redo(); 381 undoRedoStack_.Redo();
358 widget.NotifyContentChanged(); 382 widget.NotifyContentChanged();
359 } 383 }
360 break; 384 break;
361 385
362 case 'z': 386 case 'z':
363 if (modifiers & KeyboardModifiers_Control) 387 if (modifiers & KeyboardModifiers_Control)
364 { 388 {
365 undoRedoStack_.Undo(); 389 undoRedoStack_.Undo();
366 widget.NotifyContentChanged(); 390 widget.NotifyContentChanged();
367 } 391 }
368 break; 392 break;
369 393
370 default: 394 default:
371 break; 395 break;
372 } 396 }
373 } 397 }
374 }; 398 };
375 399
376 400
377 401
378 class SingleFrameEditorApplication : 402 class SingleFrameEditorApplication :
379 public SampleSingleCanvasApplicationBase, 403 public SampleSingleCanvasApplicationBase,
380 public IObserver 404 public IObserver
381 { 405 {
382 private: 406 private:
383 boost::shared_ptr<RadiographyScene> scene_; 407 boost::shared_ptr<RadiographyScene> scene_;
384 RadiographyEditorInteractor interactor_; 408 RadiographyEditorInteractor interactor_;
409 Orthanc::FontRegistry fontRegistry_;
385 410
386 public: 411 public:
387 SingleFrameEditorApplication(MessageBroker& broker) : 412 SingleFrameEditorApplication(MessageBroker& broker) :
388 IObserver(broker), 413 IObserver(broker),
389 interactor_(broker) 414 interactor_(broker)
397 422
398 virtual void DeclareStartupOptions(boost::program_options::options_description& options) 423 virtual void DeclareStartupOptions(boost::program_options::options_description& options)
399 { 424 {
400 boost::program_options::options_description generic("Sample options"); 425 boost::program_options::options_description generic("Sample options");
401 generic.add_options() 426 generic.add_options()
402 ("instance", boost::program_options::value<std::string>(), 427 ("instance", boost::program_options::value<std::string>(),
403 "Orthanc ID of the instance") 428 "Orthanc ID of the instance")
404 ("frame", boost::program_options::value<unsigned int>()->default_value(0), 429 ("frame", boost::program_options::value<unsigned int>()->default_value(0),
405 "Number of the frame, for multi-frame DICOM instances") 430 "Number of the frame, for multi-frame DICOM instances")
406 ; 431 ;
407 432
408 options.add(generic); 433 options.add(generic);
409 } 434 }
410 435
411 virtual void Initialize(StoneApplicationContext* context, 436 virtual void Initialize(StoneApplicationContext* context,
438 } 463 }
439 464
440 std::string instance = parameters["instance"].as<std::string>(); 465 std::string instance = parameters["instance"].as<std::string>();
441 int frame = parameters["frame"].as<unsigned int>(); 466 int frame = parameters["frame"].as<unsigned int>();
442 467
443 Orthanc::FontRegistry fonts; 468 fontRegistry_.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
444 fonts.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
445 469
446 scene_.reset(new RadiographyScene(GetBroker())); 470 scene_.reset(new RadiographyScene(GetBroker()));
447 //scene_->LoadDicomFrame(instance, frame, false); //.SetPan(200, 0); 471 //scene_->LoadDicomFrame(instance, frame, false); //.SetPan(200, 0);
448 scene_->LoadDicomFrame(context->GetOrthancApiClient(), "61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", 0, false); 472 scene_->LoadDicomFrame(context->GetOrthancApiClient(), "61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", 0, false, NULL);
449 473
450 #if !defined(ORTHANC_ENABLE_WASM) || ORTHANC_ENABLE_WASM != 1 474 #if !defined(ORTHANC_ENABLE_WASM) || ORTHANC_ENABLE_WASM != 1
451 Orthanc::HttpClient::ConfigureSsl(true, "/etc/ssl/certs/ca-certificates.crt"); 475 Orthanc::HttpClient::ConfigureSsl(true, "/etc/ssl/certs/ca-certificates.crt");
452 #endif 476 #endif
453 477
454 //scene_->LoadDicomWebFrame(context->GetWebService()); 478 //scene_->LoadDicomWebFrame(context->GetWebService());
455 479
456 { 480 {
457 RadiographyLayer& layer = scene_->LoadText(fonts.GetFont(0), "Hello\nworld"); 481 RadiographyLayer& layer = scene_->LoadText(fontRegistry_.GetFont(0), "Hello\nworld", NULL);
458 layer.SetResizeable(true); 482 layer.SetResizeable(true);
459 } 483 }
460 484
461 { 485 {
462 RadiographyLayer& layer = scene_->LoadTestBlock(100, 50); 486 RadiographyLayer& layer = scene_->LoadTestBlock(100, 50, NULL);
463 layer.SetResizeable(true); 487 layer.SetResizeable(true);
464 layer.SetPan(0, 200); 488 layer.SetPan(0, 200);
465 } 489 }
466 490
467 491