Mercurial > hg > orthanc-stone
comparison Applications/Samples/SingleFrameEditorApplication.h @ 407:842a3c7cfdc0
renames
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 12 Nov 2018 11:44:20 +0100 |
parents | 99e31898910e |
children | 6834c236b36d |
comparison
equal
deleted
inserted
replaced
406:5d359b115b29 | 407:842a3c7cfdc0 |
---|---|
37 #include <Core/OrthancException.h> | 37 #include <Core/OrthancException.h> |
38 #include <Core/Toolbox.h> | 38 #include <Core/Toolbox.h> |
39 #include <Plugins/Samples/Common/DicomDatasetReader.h> | 39 #include <Plugins/Samples/Common/DicomDatasetReader.h> |
40 #include <Plugins/Samples/Common/FullOrthancDataset.h> | 40 #include <Plugins/Samples/Common/FullOrthancDataset.h> |
41 | 41 |
42 | |
43 // Export using PAM is faster than using PNG, but requires Orthanc | |
44 // core >= 1.4.3 | |
42 #define EXPORT_USING_PAM 1 | 45 #define EXPORT_USING_PAM 1 |
43 | 46 |
44 | 47 |
45 #include <boost/math/constants/constants.hpp> | 48 #include <boost/math/constants/constants.hpp> |
46 #include <boost/math/special_functions/round.hpp> | 49 #include <boost/math/special_functions/round.hpp> |
47 | 50 |
48 | 51 |
49 namespace OrthancStone | 52 namespace OrthancStone |
50 { | 53 { |
51 class BitmapStack : | 54 class RadiologyScene : |
52 public IObserver, | 55 public IObserver, |
53 public IObservable | 56 public IObservable |
54 { | 57 { |
55 public: | 58 public: |
56 typedef OriginMessage<MessageType_Widget_GeometryChanged, BitmapStack> GeometryChangedMessage; | 59 typedef OriginMessage<MessageType_Widget_GeometryChanged, RadiologyScene> GeometryChangedMessage; |
57 typedef OriginMessage<MessageType_Widget_ContentChanged, BitmapStack> ContentChangedMessage; | 60 typedef OriginMessage<MessageType_Widget_ContentChanged, RadiologyScene> ContentChangedMessage; |
58 | 61 |
59 | 62 |
60 enum Corner | 63 enum Corner |
61 { | 64 { |
62 Corner_TopLeft, | 65 Corner_TopLeft, |
65 Corner_BottomRight | 68 Corner_BottomRight |
66 }; | 69 }; |
67 | 70 |
68 | 71 |
69 | 72 |
70 class Bitmap : public boost::noncopyable | 73 class Layer : public boost::noncopyable |
71 { | 74 { |
75 friend class RadiologyScene; | |
76 | |
72 private: | 77 private: |
73 size_t index_; | 78 size_t index_; |
74 bool hasSize_; | 79 bool hasSize_; |
75 unsigned int width_; | 80 unsigned int width_; |
76 unsigned int height_; | 81 unsigned int height_; |
185 | 190 |
186 ApplyTransform(x, y, transform_); | 191 ApplyTransform(x, y, transform_); |
187 } | 192 } |
188 | 193 |
189 | 194 |
195 void SetIndex(size_t index) | |
196 { | |
197 index_ = index; | |
198 } | |
199 | |
200 | |
201 bool Contains(double x, | |
202 double y) const | |
203 { | |
204 ApplyTransform(x, y, transformInverse_); | |
205 | |
206 unsigned int cropX, cropY, cropWidth, cropHeight; | |
207 GetCrop(cropX, cropY, cropWidth, cropHeight); | |
208 | |
209 return (x >= cropX && x <= cropX + cropWidth && | |
210 y >= cropY && y <= cropY + cropHeight); | |
211 } | |
212 | |
213 | |
214 void DrawBorders(CairoContext& context, | |
215 double zoom) | |
216 { | |
217 unsigned int cx, cy, width, height; | |
218 GetCrop(cx, cy, width, height); | |
219 | |
220 double dx = static_cast<double>(cx); | |
221 double dy = static_cast<double>(cy); | |
222 double dwidth = static_cast<double>(width); | |
223 double dheight = static_cast<double>(height); | |
224 | |
225 cairo_t* cr = context.GetObject(); | |
226 cairo_set_line_width(cr, 2.0 / zoom); | |
227 | |
228 double x, y; | |
229 x = dx; | |
230 y = dy; | |
231 ApplyTransform(x, y, transform_); | |
232 cairo_move_to(cr, x, y); | |
233 | |
234 x = dx + dwidth; | |
235 y = dy; | |
236 ApplyTransform(x, y, transform_); | |
237 cairo_line_to(cr, x, y); | |
238 | |
239 x = dx + dwidth; | |
240 y = dy + dheight; | |
241 ApplyTransform(x, y, transform_); | |
242 cairo_line_to(cr, x, y); | |
243 | |
244 x = dx; | |
245 y = dy + dheight; | |
246 ApplyTransform(x, y, transform_); | |
247 cairo_line_to(cr, x, y); | |
248 | |
249 x = dx; | |
250 y = dy; | |
251 ApplyTransform(x, y, transform_); | |
252 cairo_line_to(cr, x, y); | |
253 | |
254 cairo_stroke(cr); | |
255 } | |
256 | |
257 | |
258 static double Square(double x) | |
259 { | |
260 return x * x; | |
261 } | |
262 | |
263 | |
190 public: | 264 public: |
191 Bitmap() : | 265 Layer() : |
192 index_(0), | 266 index_(0), |
193 hasSize_(false), | 267 hasSize_(false), |
194 width_(0), | 268 width_(0), |
195 height_(0), | 269 height_(0), |
196 hasCrop_(false), | 270 hasCrop_(false), |
202 resizeable_(false) | 276 resizeable_(false) |
203 { | 277 { |
204 UpdateTransform(); | 278 UpdateTransform(); |
205 } | 279 } |
206 | 280 |
207 virtual ~Bitmap() | 281 virtual ~Layer() |
208 { | 282 { |
209 } | |
210 | |
211 void SetIndex(size_t index) | |
212 { | |
213 index_ = index; | |
214 } | 283 } |
215 | 284 |
216 size_t GetIndex() const | 285 size_t GetIndex() const |
217 { | 286 { |
218 return index_; | 287 return index_; |
308 { | 377 { |
309 return height_; | 378 return height_; |
310 } | 379 } |
311 | 380 |
312 | 381 |
313 void CheckSize(unsigned int width, | |
314 unsigned int height) | |
315 { | |
316 if (hasSize_ && | |
317 (width != width_ || | |
318 height != height_)) | |
319 { | |
320 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize); | |
321 } | |
322 } | |
323 | |
324 | |
325 Extent2D GetExtent() const | 382 Extent2D GetExtent() const |
326 { | 383 { |
327 Extent2D extent; | 384 Extent2D extent; |
328 | 385 |
329 unsigned int x, y, width, height; | 386 unsigned int x, y, width, height; |
341 | 398 |
342 return extent; | 399 return extent; |
343 } | 400 } |
344 | 401 |
345 | 402 |
346 bool Contains(double x, | |
347 double y) const | |
348 { | |
349 ApplyTransform(x, y, transformInverse_); | |
350 | |
351 unsigned int cropX, cropY, cropWidth, cropHeight; | |
352 GetCrop(cropX, cropY, cropWidth, cropHeight); | |
353 | |
354 return (x >= cropX && x <= cropX + cropWidth && | |
355 y >= cropY && y <= cropY + cropHeight); | |
356 } | |
357 | |
358 | |
359 bool GetPixel(unsigned int& imageX, | 403 bool GetPixel(unsigned int& imageX, |
360 unsigned int& imageY, | 404 unsigned int& imageY, |
361 double sceneX, | 405 double sceneX, |
362 double sceneY) const | 406 double sceneY) const |
363 { | 407 { |
445 double& centerY) const | 489 double& centerY) const |
446 { | 490 { |
447 centerX = static_cast<double>(width_) / 2.0; | 491 centerX = static_cast<double>(width_) / 2.0; |
448 centerY = static_cast<double>(height_) / 2.0; | 492 centerY = static_cast<double>(height_) / 2.0; |
449 ApplyTransform(centerX, centerY, transform_); | 493 ApplyTransform(centerX, centerY, transform_); |
450 } | |
451 | |
452 | |
453 void DrawBorders(CairoContext& context, | |
454 double zoom) | |
455 { | |
456 unsigned int cx, cy, width, height; | |
457 GetCrop(cx, cy, width, height); | |
458 | |
459 double dx = static_cast<double>(cx); | |
460 double dy = static_cast<double>(cy); | |
461 double dwidth = static_cast<double>(width); | |
462 double dheight = static_cast<double>(height); | |
463 | |
464 cairo_t* cr = context.GetObject(); | |
465 cairo_set_line_width(cr, 2.0 / zoom); | |
466 | |
467 double x, y; | |
468 x = dx; | |
469 y = dy; | |
470 ApplyTransform(x, y, transform_); | |
471 cairo_move_to(cr, x, y); | |
472 | |
473 x = dx + dwidth; | |
474 y = dy; | |
475 ApplyTransform(x, y, transform_); | |
476 cairo_line_to(cr, x, y); | |
477 | |
478 x = dx + dwidth; | |
479 y = dy + dheight; | |
480 ApplyTransform(x, y, transform_); | |
481 cairo_line_to(cr, x, y); | |
482 | |
483 x = dx; | |
484 y = dy + dheight; | |
485 ApplyTransform(x, y, transform_); | |
486 cairo_line_to(cr, x, y); | |
487 | |
488 x = dx; | |
489 y = dy; | |
490 ApplyTransform(x, y, transform_); | |
491 cairo_line_to(cr, x, y); | |
492 | |
493 cairo_stroke(cr); | |
494 } | |
495 | |
496 | |
497 static double Square(double x) | |
498 { | |
499 return x * x; | |
500 } | 494 } |
501 | 495 |
502 | 496 |
503 void GetCorner(double& x /* out */, | 497 void GetCorner(double& x /* out */, |
504 double& y /* out */, | 498 double& y /* out */, |
554 { | 548 { |
555 resizeable_ = resizeable; | 549 resizeable_ = resizeable; |
556 } | 550 } |
557 | 551 |
558 virtual bool GetDefaultWindowing(float& center, | 552 virtual bool GetDefaultWindowing(float& center, |
559 float& width) const | 553 float& width) const = 0; |
560 { | |
561 return false; | |
562 } | |
563 | 554 |
564 virtual void Render(Orthanc::ImageAccessor& buffer, | 555 virtual void Render(Orthanc::ImageAccessor& buffer, |
565 const Matrix& viewTransform, | 556 const Matrix& viewTransform, |
566 ImageInterpolation interpolation) const = 0; | 557 ImageInterpolation interpolation) const = 0; |
567 | 558 |
568 virtual bool GetRange(float& minValue, | 559 virtual bool GetRange(float& minValue, |
569 float& maxValue) const = 0; | 560 float& maxValue) const = 0; |
570 }; | 561 }; |
571 | 562 |
572 | 563 |
573 class BitmapAccessor : public boost::noncopyable | 564 class LayerAccessor : public boost::noncopyable |
574 { | 565 { |
575 private: | 566 private: |
576 BitmapStack& stack_; | 567 RadiologyScene& scene_; |
577 size_t index_; | 568 size_t index_; |
578 Bitmap* bitmap_; | 569 Layer* layer_; |
579 | 570 |
580 public: | 571 public: |
581 BitmapAccessor(BitmapStack& stack, | 572 LayerAccessor(RadiologyScene& scene, |
582 size_t index) : | 573 size_t index) : |
583 stack_(stack), | 574 scene_(scene), |
584 index_(index) | 575 index_(index) |
585 { | 576 { |
586 Bitmaps::iterator bitmap = stack.bitmaps_.find(index); | 577 Layers::iterator layer = scene.layers_.find(index); |
587 if (bitmap == stack.bitmaps_.end()) | 578 if (layer == scene.layers_.end()) |
588 { | 579 { |
589 bitmap_ = NULL; | 580 layer_ = NULL; |
590 } | 581 } |
591 else | 582 else |
592 { | 583 { |
593 assert(bitmap->second != NULL); | 584 assert(layer->second != NULL); |
594 bitmap_ = bitmap->second; | 585 layer_ = layer->second; |
595 } | 586 } |
596 } | 587 } |
597 | 588 |
598 BitmapAccessor(BitmapStack& stack, | 589 LayerAccessor(RadiologyScene& scene, |
599 double x, | 590 double x, |
600 double y) : | 591 double y) : |
601 stack_(stack), | 592 scene_(scene), |
602 index_(0) // Dummy initialization | 593 index_(0) // Dummy initialization |
603 { | 594 { |
604 if (stack.LookupBitmap(index_, x, y)) | 595 if (scene.LookupLayer(index_, x, y)) |
605 { | 596 { |
606 Bitmaps::iterator bitmap = stack.bitmaps_.find(index_); | 597 Layers::iterator layer = scene.layers_.find(index_); |
607 | 598 |
608 if (bitmap == stack.bitmaps_.end()) | 599 if (layer == scene.layers_.end()) |
609 { | 600 { |
610 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 601 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
611 } | 602 } |
612 else | 603 else |
613 { | 604 { |
614 assert(bitmap->second != NULL); | 605 assert(layer->second != NULL); |
615 bitmap_ = bitmap->second; | 606 layer_ = layer->second; |
616 } | 607 } |
617 } | 608 } |
618 else | 609 else |
619 { | 610 { |
620 bitmap_ = NULL; | 611 layer_ = NULL; |
621 } | 612 } |
622 } | 613 } |
623 | 614 |
624 void Invalidate() | 615 void Invalidate() |
625 { | 616 { |
626 bitmap_ = NULL; | 617 layer_ = NULL; |
627 } | 618 } |
628 | 619 |
629 bool IsValid() const | 620 bool IsValid() const |
630 { | 621 { |
631 return bitmap_ != NULL; | 622 return layer_ != NULL; |
632 } | 623 } |
633 | 624 |
634 BitmapStack& GetStack() const | 625 RadiologyScene& GetScene() const |
635 { | 626 { |
636 if (IsValid()) | 627 if (IsValid()) |
637 { | 628 { |
638 return stack_; | 629 return scene_; |
639 } | 630 } |
640 else | 631 else |
641 { | 632 { |
642 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 633 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
643 } | 634 } |
653 { | 644 { |
654 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 645 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
655 } | 646 } |
656 } | 647 } |
657 | 648 |
658 Bitmap& GetBitmap() const | 649 Layer& GetLayer() const |
659 { | 650 { |
660 if (IsValid()) | 651 if (IsValid()) |
661 { | 652 { |
662 return *bitmap_; | 653 return *layer_; |
663 } | 654 } |
664 else | 655 else |
665 { | 656 { |
666 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 657 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
667 } | 658 } |
668 } | 659 } |
669 }; | 660 }; |
670 | 661 |
671 | 662 |
672 class AlphaBitmap : public Bitmap | 663 private: |
664 class AlphaLayer : public Layer | |
673 { | 665 { |
674 private: | 666 private: |
675 const BitmapStack& stack_; | 667 const RadiologyScene& scene_; |
676 std::auto_ptr<Orthanc::ImageAccessor> alpha_; // Grayscale8 | 668 std::auto_ptr<Orthanc::ImageAccessor> alpha_; // Grayscale8 |
677 bool useWindowing_; | 669 bool useWindowing_; |
678 float foreground_; | 670 float foreground_; |
679 | 671 |
680 public: | 672 public: |
681 AlphaBitmap(const BitmapStack& stack) : | 673 AlphaLayer(const RadiologyScene& scene) : |
682 stack_(stack), | 674 scene_(scene), |
683 useWindowing_(true), | 675 useWindowing_(true), |
684 foreground_(0) | 676 foreground_(0) |
685 { | 677 { |
686 } | 678 } |
687 | 679 |
716 const std::string& utf8) | 708 const std::string& utf8) |
717 { | 709 { |
718 SetAlpha(font.RenderAlpha(utf8)); | 710 SetAlpha(font.RenderAlpha(utf8)); |
719 } | 711 } |
720 | 712 |
713 | |
714 virtual bool GetDefaultWindowing(float& center, | |
715 float& width) const | |
716 { | |
717 return false; | |
718 } | |
719 | |
721 | 720 |
722 virtual void Render(Orthanc::ImageAccessor& buffer, | 721 virtual void Render(Orthanc::ImageAccessor& buffer, |
723 const Matrix& viewTransform, | 722 const Matrix& viewTransform, |
724 ImageInterpolation interpolation) const | 723 ImageInterpolation interpolation) const |
725 { | 724 { |
753 float value = foreground_; | 752 float value = foreground_; |
754 | 753 |
755 if (useWindowing_) | 754 if (useWindowing_) |
756 { | 755 { |
757 float center, width; | 756 float center, width; |
758 if (stack_.GetWindowing(center, width)) | 757 if (scene_.GetWindowing(center, width)) |
759 { | 758 { |
760 value = center + width / 2.0f; | 759 value = center + width / 2.0f; |
761 } | 760 } |
762 } | 761 } |
763 | 762 |
773 *q = (a * value + (1.0f - a) * (*q)); | 772 *q = (a * value + (1.0f - a) * (*q)); |
774 } | 773 } |
775 } | 774 } |
776 } | 775 } |
777 | 776 |
777 | |
778 virtual bool GetRange(float& minValue, | 778 virtual bool GetRange(float& minValue, |
779 float& maxValue) const | 779 float& maxValue) const |
780 { | 780 { |
781 if (useWindowing_) | 781 if (useWindowing_) |
782 { | 782 { |
834 LinearAlgebra::FillMatrix(m, 3, 3, v); | 834 LinearAlgebra::FillMatrix(m, 3, 3, v); |
835 return m; | 835 return m; |
836 } | 836 } |
837 | 837 |
838 | 838 |
839 class DicomBitmap : public Bitmap | 839 class DicomLayer : public Layer |
840 { | 840 { |
841 private: | 841 private: |
842 std::auto_ptr<Orthanc::ImageAccessor> source_; // Content of PixelData | 842 std::auto_ptr<Orthanc::ImageAccessor> source_; // Content of PixelData |
843 std::auto_ptr<DicomFrameConverter> converter_; | 843 std::auto_ptr<DicomFrameConverter> converter_; |
844 std::auto_ptr<Orthanc::ImageAccessor> converted_; // Float32 | 844 std::auto_ptr<Orthanc::ImageAccessor> converted_; // Float32 |
972 }; | 972 }; |
973 | 973 |
974 | 974 |
975 | 975 |
976 | 976 |
977 typedef std::map<size_t, Bitmap*> Bitmaps; | 977 typedef std::map<size_t, Layer*> Layers; |
978 | 978 |
979 OrthancApiClient& orthanc_; | 979 OrthancApiClient& orthanc_; |
980 size_t countBitmaps_; | 980 size_t countLayers_; |
981 bool hasWindowing_; | 981 bool hasWindowing_; |
982 float windowingCenter_; | 982 float windowingCenter_; |
983 float windowingWidth_; | 983 float windowingWidth_; |
984 Bitmaps bitmaps_; | 984 Layers layers_; |
985 | |
986 | |
987 Layer& RegisterLayer(Layer* layer) | |
988 { | |
989 if (layer == NULL) | |
990 { | |
991 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
992 } | |
993 | |
994 std::auto_ptr<Layer> raii(layer); | |
995 | |
996 size_t index = countLayers_++; | |
997 raii->SetIndex(index); | |
998 layers_[index] = raii.release(); | |
999 | |
1000 EmitMessage(GeometryChangedMessage(*this)); | |
1001 EmitMessage(ContentChangedMessage(*this)); | |
1002 | |
1003 return *layer; | |
1004 } | |
1005 | |
985 | 1006 |
986 public: | 1007 public: |
987 BitmapStack(MessageBroker& broker, | 1008 RadiologyScene(MessageBroker& broker, |
988 OrthancApiClient& orthanc) : | 1009 OrthancApiClient& orthanc) : |
989 IObserver(broker), | 1010 IObserver(broker), |
990 IObservable(broker), | 1011 IObservable(broker), |
991 orthanc_(orthanc), | 1012 orthanc_(orthanc), |
992 countBitmaps_(0), | 1013 countLayers_(0), |
993 hasWindowing_(false), | 1014 hasWindowing_(false), |
994 windowingCenter_(0), // Dummy initialization | 1015 windowingCenter_(0), // Dummy initialization |
995 windowingWidth_(0) // Dummy initialization | 1016 windowingWidth_(0) // Dummy initialization |
996 { | 1017 { |
997 } | 1018 } |
998 | 1019 |
999 | 1020 |
1000 virtual ~BitmapStack() | 1021 virtual ~RadiologyScene() |
1001 { | 1022 { |
1002 for (Bitmaps::iterator it = bitmaps_.begin(); it != bitmaps_.end(); it++) | 1023 for (Layers::iterator it = layers_.begin(); it != layers_.end(); it++) |
1003 { | 1024 { |
1004 assert(it->second != NULL); | 1025 assert(it->second != NULL); |
1005 delete it->second; | 1026 delete it->second; |
1006 } | 1027 } |
1007 } | 1028 } |
1042 windowingCenter_ = center; | 1063 windowingCenter_ = center; |
1043 windowingWidth_ = width; | 1064 windowingWidth_ = width; |
1044 } | 1065 } |
1045 | 1066 |
1046 | 1067 |
1047 Bitmap& RegisterBitmap(Bitmap* bitmap) | 1068 Layer& LoadText(const Orthanc::Font& font, |
1048 { | 1069 const std::string& utf8) |
1049 if (bitmap == NULL) | 1070 { |
1050 { | 1071 std::auto_ptr<AlphaLayer> alpha(new AlphaLayer(*this)); |
1051 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 1072 alpha->LoadText(font, utf8); |
1052 } | 1073 |
1053 | 1074 return RegisterLayer(alpha.release()); |
1054 std::auto_ptr<Bitmap> raii(bitmap); | 1075 } |
1055 | 1076 |
1056 size_t index = countBitmaps_++; | |
1057 raii->SetIndex(index); | |
1058 bitmaps_[index] = raii.release(); | |
1059 | |
1060 EmitMessage(GeometryChangedMessage(*this)); | |
1061 EmitMessage(ContentChangedMessage(*this)); | |
1062 | |
1063 return *bitmap; | |
1064 } | |
1065 | 1077 |
1066 | 1078 Layer& LoadTestBlock(unsigned int width, |
1067 Bitmap& LoadText(const Orthanc::Font& font, | 1079 unsigned int height) |
1068 const std::string& utf8) | |
1069 { | |
1070 std::auto_ptr<AlphaBitmap> alpha(new AlphaBitmap(*this)); | |
1071 alpha->LoadText(font, utf8); | |
1072 | |
1073 return RegisterBitmap(alpha.release()); | |
1074 } | |
1075 | |
1076 | |
1077 Bitmap& LoadTestBlock(unsigned int width, | |
1078 unsigned int height) | |
1079 { | 1080 { |
1080 std::auto_ptr<Orthanc::Image> block(new Orthanc::Image(Orthanc::PixelFormat_Grayscale8, width, height, false)); | 1081 std::auto_ptr<Orthanc::Image> block(new Orthanc::Image(Orthanc::PixelFormat_Grayscale8, width, height, false)); |
1081 | 1082 |
1082 for (unsigned int padding = 0; | 1083 for (unsigned int padding = 0; |
1083 (width > 2 * padding) && (height > 2 * padding); | 1084 (width > 2 * padding) && (height > 2 * padding); |
1096 Orthanc::ImageAccessor region; | 1097 Orthanc::ImageAccessor region; |
1097 block->GetRegion(region, padding, padding, width - 2 * padding, height - 2 * padding); | 1098 block->GetRegion(region, padding, padding, width - 2 * padding, height - 2 * padding); |
1098 Orthanc::ImageProcessing::Set(region, color); | 1099 Orthanc::ImageProcessing::Set(region, color); |
1099 } | 1100 } |
1100 | 1101 |
1101 std::auto_ptr<AlphaBitmap> alpha(new AlphaBitmap(*this)); | 1102 std::auto_ptr<AlphaLayer> alpha(new AlphaLayer(*this)); |
1102 alpha->SetAlpha(block.release()); | 1103 alpha->SetAlpha(block.release()); |
1103 | 1104 |
1104 return RegisterBitmap(alpha.release()); | 1105 return RegisterLayer(alpha.release()); |
1105 } | 1106 } |
1106 | 1107 |
1107 | 1108 |
1108 Bitmap& LoadFrame(const std::string& instance, | 1109 Layer& LoadDicomFrame(const std::string& instance, |
1109 unsigned int frame, | 1110 unsigned int frame, |
1110 bool httpCompression) | 1111 bool httpCompression) |
1111 { | 1112 { |
1112 Bitmap& bitmap = RegisterBitmap(new DicomBitmap); | 1113 Layer& layer = RegisterLayer(new DicomLayer); |
1113 | 1114 |
1114 { | 1115 { |
1115 IWebService::Headers headers; | 1116 IWebService::Headers headers; |
1116 std::string uri = "/instances/" + instance + "/tags"; | 1117 std::string uri = "/instances/" + instance + "/tags"; |
1117 orthanc_.GetBinaryAsync(uri, headers, | 1118 orthanc_.GetBinaryAsync(uri, headers, |
1118 new Callable<BitmapStack, OrthancApiClient::BinaryResponseReadyMessage> | 1119 new Callable<RadiologyScene, OrthancApiClient::BinaryResponseReadyMessage> |
1119 (*this, &BitmapStack::OnTagsReceived), NULL, | 1120 (*this, &RadiologyScene::OnTagsReceived), NULL, |
1120 new Orthanc::SingleValueObject<size_t>(bitmap.GetIndex())); | 1121 new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); |
1121 } | 1122 } |
1122 | 1123 |
1123 { | 1124 { |
1124 IWebService::Headers headers; | 1125 IWebService::Headers headers; |
1125 headers["Accept"] = "image/x-portable-arbitrarymap"; | 1126 headers["Accept"] = "image/x-portable-arbitrarymap"; |
1129 headers["Accept-Encoding"] = "gzip"; | 1130 headers["Accept-Encoding"] = "gzip"; |
1130 } | 1131 } |
1131 | 1132 |
1132 std::string uri = "/instances/" + instance + "/frames/" + boost::lexical_cast<std::string>(frame) + "/image-uint16"; | 1133 std::string uri = "/instances/" + instance + "/frames/" + boost::lexical_cast<std::string>(frame) + "/image-uint16"; |
1133 orthanc_.GetBinaryAsync(uri, headers, | 1134 orthanc_.GetBinaryAsync(uri, headers, |
1134 new Callable<BitmapStack, OrthancApiClient::BinaryResponseReadyMessage> | 1135 new Callable<RadiologyScene, OrthancApiClient::BinaryResponseReadyMessage> |
1135 (*this, &BitmapStack::OnFrameReceived), NULL, | 1136 (*this, &RadiologyScene::OnFrameReceived), NULL, |
1136 new Orthanc::SingleValueObject<size_t>(bitmap.GetIndex())); | 1137 new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); |
1137 } | 1138 } |
1138 | 1139 |
1139 return bitmap; | 1140 return layer; |
1140 } | 1141 } |
1141 | 1142 |
1142 | 1143 |
1143 void OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) | 1144 void OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) |
1144 { | 1145 { |
1145 size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue(); | 1146 size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue(); |
1146 | 1147 |
1147 LOG(INFO) << "JSON received: " << message.GetUri().c_str() | 1148 LOG(INFO) << "JSON received: " << message.GetUri().c_str() |
1148 << " (" << message.GetAnswerSize() << " bytes) for bitmap " << index; | 1149 << " (" << message.GetAnswerSize() << " bytes) for layer " << index; |
1149 | 1150 |
1150 Bitmaps::iterator bitmap = bitmaps_.find(index); | 1151 Layers::iterator layer = layers_.find(index); |
1151 if (bitmap != bitmaps_.end()) | 1152 if (layer != layers_.end()) |
1152 { | 1153 { |
1153 assert(bitmap->second != NULL); | 1154 assert(layer->second != NULL); |
1154 | 1155 |
1155 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer(), message.GetAnswerSize()); | 1156 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer(), message.GetAnswerSize()); |
1156 dynamic_cast<DicomBitmap*>(bitmap->second)->SetDicomTags(dicom); | 1157 dynamic_cast<DicomLayer*>(layer->second)->SetDicomTags(dicom); |
1157 | 1158 |
1158 float c, w; | 1159 float c, w; |
1159 if (!hasWindowing_ && | 1160 if (!hasWindowing_ && |
1160 bitmap->second->GetDefaultWindowing(c, w)) | 1161 layer->second->GetDefaultWindowing(c, w)) |
1161 { | 1162 { |
1162 hasWindowing_ = true; | 1163 hasWindowing_ = true; |
1163 windowingCenter_ = c; | 1164 windowingCenter_ = c; |
1164 windowingWidth_ = w; | 1165 windowingWidth_ = w; |
1165 } | 1166 } |
1172 void OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) | 1173 void OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) |
1173 { | 1174 { |
1174 size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue(); | 1175 size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue(); |
1175 | 1176 |
1176 LOG(INFO) << "DICOM frame received: " << message.GetUri().c_str() | 1177 LOG(INFO) << "DICOM frame received: " << message.GetUri().c_str() |
1177 << " (" << message.GetAnswerSize() << " bytes) for bitmap " << index; | 1178 << " (" << message.GetAnswerSize() << " bytes) for layer " << index; |
1178 | 1179 |
1179 Bitmaps::iterator bitmap = bitmaps_.find(index); | 1180 Layers::iterator layer = layers_.find(index); |
1180 if (bitmap != bitmaps_.end()) | 1181 if (layer != layers_.end()) |
1181 { | 1182 { |
1182 assert(bitmap->second != NULL); | 1183 assert(layer->second != NULL); |
1183 | 1184 |
1184 std::string content; | 1185 std::string content; |
1185 if (message.GetAnswerSize() > 0) | 1186 if (message.GetAnswerSize() > 0) |
1186 { | 1187 { |
1187 content.assign(reinterpret_cast<const char*>(message.GetAnswer()), message.GetAnswerSize()); | 1188 content.assign(reinterpret_cast<const char*>(message.GetAnswer()), message.GetAnswerSize()); |
1188 } | 1189 } |
1189 | 1190 |
1190 std::auto_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader); | 1191 std::auto_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader); |
1191 reader->ReadFromMemory(content); | 1192 reader->ReadFromMemory(content); |
1192 dynamic_cast<DicomBitmap*>(bitmap->second)->SetSourceImage(reader.release()); | 1193 dynamic_cast<DicomLayer*>(layer->second)->SetSourceImage(reader.release()); |
1193 | 1194 |
1194 EmitMessage(ContentChangedMessage(*this)); | 1195 EmitMessage(ContentChangedMessage(*this)); |
1195 } | 1196 } |
1196 } | 1197 } |
1197 | 1198 |
1198 | 1199 |
1199 Extent2D GetSceneExtent() const | 1200 Extent2D GetSceneExtent() const |
1200 { | 1201 { |
1201 Extent2D extent; | 1202 Extent2D extent; |
1202 | 1203 |
1203 for (Bitmaps::const_iterator it = bitmaps_.begin(); | 1204 for (Layers::const_iterator it = layers_.begin(); |
1204 it != bitmaps_.end(); ++it) | 1205 it != layers_.end(); ++it) |
1205 { | 1206 { |
1206 assert(it->second != NULL); | 1207 assert(it->second != NULL); |
1207 extent.Union(it->second->GetExtent()); | 1208 extent.Union(it->second->GetExtent()); |
1208 } | 1209 } |
1209 | 1210 |
1216 ImageInterpolation interpolation) const | 1217 ImageInterpolation interpolation) const |
1217 { | 1218 { |
1218 Orthanc::ImageProcessing::Set(buffer, 0); | 1219 Orthanc::ImageProcessing::Set(buffer, 0); |
1219 | 1220 |
1220 // Render layers in the background-to-foreground order | 1221 // Render layers in the background-to-foreground order |
1221 for (size_t index = 0; index < countBitmaps_; index++) | 1222 for (size_t index = 0; index < countLayers_; index++) |
1222 { | 1223 { |
1223 Bitmaps::const_iterator it = bitmaps_.find(index); | 1224 Layers::const_iterator it = layers_.find(index); |
1224 if (it != bitmaps_.end()) | 1225 if (it != layers_.end()) |
1225 { | 1226 { |
1226 assert(it->second != NULL); | 1227 assert(it->second != NULL); |
1227 it->second->Render(buffer, viewTransform, interpolation); | 1228 it->second->Render(buffer, viewTransform, interpolation); |
1228 } | 1229 } |
1229 } | 1230 } |
1230 } | 1231 } |
1231 | 1232 |
1232 | 1233 |
1233 bool LookupBitmap(size_t& index /* out */, | 1234 bool LookupLayer(size_t& index /* out */, |
1234 double x, | 1235 double x, |
1235 double y) const | 1236 double y) const |
1236 { | 1237 { |
1237 // Render layers in the foreground-to-background order | 1238 // Render layers in the foreground-to-background order |
1238 for (size_t i = countBitmaps_; i > 0; i--) | 1239 for (size_t i = countLayers_; i > 0; i--) |
1239 { | 1240 { |
1240 index = i - 1; | 1241 index = i - 1; |
1241 Bitmaps::const_iterator it = bitmaps_.find(index); | 1242 Layers::const_iterator it = layers_.find(index); |
1242 if (it != bitmaps_.end()) | 1243 if (it != layers_.end()) |
1243 { | 1244 { |
1244 assert(it->second != NULL); | 1245 assert(it->second != NULL); |
1245 if (it->second->Contains(x, y)) | 1246 if (it->second->Contains(x, y)) |
1246 { | 1247 { |
1247 return true; | 1248 return true; |
1252 return false; | 1253 return false; |
1253 } | 1254 } |
1254 | 1255 |
1255 | 1256 |
1256 void DrawBorder(CairoContext& context, | 1257 void DrawBorder(CairoContext& context, |
1257 unsigned int bitmap, | 1258 unsigned int layer, |
1258 double zoom) | 1259 double zoom) |
1259 { | 1260 { |
1260 Bitmaps::const_iterator found = bitmaps_.find(bitmap); | 1261 Layers::const_iterator found = layers_.find(layer); |
1261 | 1262 |
1262 if (found != bitmaps_.end()) | 1263 if (found != layers_.end()) |
1263 { | 1264 { |
1264 context.SetSourceColor(255, 0, 0); | 1265 context.SetSourceColor(255, 0, 0); |
1265 found->second->DrawBorders(context, zoom); | 1266 found->second->DrawBorders(context, zoom); |
1266 } | 1267 } |
1267 } | 1268 } |
1270 void GetRange(float& minValue, | 1271 void GetRange(float& minValue, |
1271 float& maxValue) const | 1272 float& maxValue) const |
1272 { | 1273 { |
1273 bool first = true; | 1274 bool first = true; |
1274 | 1275 |
1275 for (Bitmaps::const_iterator it = bitmaps_.begin(); | 1276 for (Layers::const_iterator it = layers_.begin(); |
1276 it != bitmaps_.end(); it++) | 1277 it != layers_.end(); it++) |
1277 { | 1278 { |
1278 assert(it->second != NULL); | 1279 assert(it->second != NULL); |
1279 | 1280 |
1280 float a, b; | 1281 float a, b; |
1281 if (it->second->GetRange(a, b)) | 1282 if (it->second->GetRange(a, b)) |
1300 maxValue = 0; | 1301 maxValue = 0; |
1301 } | 1302 } |
1302 } | 1303 } |
1303 | 1304 |
1304 | 1305 |
1306 // Export using PAM is faster than using PNG, but requires Orthanc | |
1307 // core >= 1.4.3 | |
1305 void Export(const Orthanc::DicomMap& dicom, | 1308 void Export(const Orthanc::DicomMap& dicom, |
1306 double pixelSpacingX, | 1309 double pixelSpacingX, |
1307 double pixelSpacingY, | 1310 double pixelSpacingY, |
1308 bool invert, | 1311 bool invert, |
1309 ImageInterpolation interpolation) | 1312 ImageInterpolation interpolation, |
1313 bool usePam) | |
1310 { | 1314 { |
1311 if (pixelSpacingX <= 0 || | 1315 if (pixelSpacingX <= 0 || |
1312 pixelSpacingY <= 0) | 1316 pixelSpacingY <= 0) |
1313 { | 1317 { |
1314 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | 1318 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); |
1315 } | 1319 } |
1316 | 1320 |
1317 LOG(WARNING) << "Exporting DICOM"; | 1321 LOG(INFO) << "Exporting DICOM"; |
1318 | 1322 |
1319 Extent2D extent = GetSceneExtent(); | 1323 Extent2D extent = GetSceneExtent(); |
1320 | 1324 |
1321 int w = std::ceil(extent.GetWidth() / pixelSpacingX); | 1325 int w = std::ceil(extent.GetWidth() / pixelSpacingX); |
1322 int h = std::ceil(extent.GetHeight() / pixelSpacingY); | 1326 int h = std::ceil(extent.GetHeight() / pixelSpacingY); |
1343 std::string base64; | 1347 std::string base64; |
1344 | 1348 |
1345 { | 1349 { |
1346 std::string content; | 1350 std::string content; |
1347 | 1351 |
1348 #if EXPORT_USING_PAM == 1 | 1352 if (usePam) |
1349 { | 1353 { |
1350 Orthanc::PamWriter writer; | 1354 Orthanc::PamWriter writer; |
1351 writer.WriteToMemory(content, rendered); | 1355 writer.WriteToMemory(content, rendered); |
1352 } | 1356 } |
1353 #else | 1357 else |
1354 { | 1358 { |
1355 Orthanc::PngWriter writer; | 1359 Orthanc::PngWriter writer; |
1356 writer.WriteToMemory(content, rendered); | 1360 writer.WriteToMemory(content, rendered); |
1357 } | 1361 } |
1358 #endif | |
1359 | 1362 |
1360 Orthanc::Toolbox::EncodeBase64(base64, content); | 1363 Orthanc::Toolbox::EncodeBase64(base64, content); |
1361 } | 1364 } |
1362 | 1365 |
1363 std::set<Orthanc::DicomTag> tags; | 1366 std::set<Orthanc::DicomTag> tags; |
1378 } | 1381 } |
1379 | 1382 |
1380 json["Tags"][Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION.Format()] = | 1383 json["Tags"][Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION.Format()] = |
1381 (invert ? "MONOCHROME1" : "MONOCHROME2"); | 1384 (invert ? "MONOCHROME1" : "MONOCHROME2"); |
1382 | 1385 |
1383 // WARNING: The order of PixelSpacing is Y/X | 1386 // WARNING: The order of PixelSpacing is Y/X. We use "%0.8f" to |
1387 // avoid floating-point numbers to grow over 16 characters, | |
1388 // which would be invalid according to DICOM standard | |
1389 // ("dciodvfy" would complain). | |
1384 char buf[32]; | 1390 char buf[32]; |
1385 sprintf(buf, "%0.8f\\%0.8f", pixelSpacingY, pixelSpacingX); | 1391 sprintf(buf, "%0.8f\\%0.8f", pixelSpacingY, pixelSpacingX); |
1386 | 1392 |
1387 json["Tags"][Orthanc::DICOM_TAG_PIXEL_SPACING.Format()] = buf; | 1393 json["Tags"][Orthanc::DICOM_TAG_PIXEL_SPACING.Format()] = buf; |
1388 | 1394 |
1394 | 1400 |
1395 json["Tags"][Orthanc::DICOM_TAG_WINDOW_WIDTH.Format()] = | 1401 json["Tags"][Orthanc::DICOM_TAG_WINDOW_WIDTH.Format()] = |
1396 boost::lexical_cast<std::string>(boost::math::iround(width)); | 1402 boost::lexical_cast<std::string>(boost::math::iround(width)); |
1397 } | 1403 } |
1398 | 1404 |
1399 #if EXPORT_USING_PAM == 1 | 1405 // This is Data URI scheme: https://en.wikipedia.org/wiki/Data_URI_scheme |
1400 json["Content"] = "data:" + std::string(Orthanc::MIME_PAM) + ";base64," + base64; | 1406 json["Content"] = ("data:" + |
1401 #else | 1407 std::string(usePam ? Orthanc::MIME_PAM : Orthanc::MIME_PNG) + |
1402 json["Content"] = "data:" + std::string(Orthanc::MIME_PNG) + ";base64," + base64; | 1408 ";base64," + base64); |
1403 #endif | |
1404 | 1409 |
1405 orthanc_.PostJsonAsyncExpectJson( | 1410 orthanc_.PostJsonAsyncExpectJson( |
1406 "/tools/create-dicom", json, | 1411 "/tools/create-dicom", json, |
1407 new Callable<BitmapStack, OrthancApiClient::JsonResponseReadyMessage> | 1412 new Callable<RadiologyScene, OrthancApiClient::JsonResponseReadyMessage> |
1408 (*this, &BitmapStack::OnDicomExported), | 1413 (*this, &RadiologyScene::OnDicomExported), |
1409 NULL, NULL); | 1414 NULL, NULL); |
1410 } | 1415 } |
1411 | 1416 |
1412 | 1417 |
1413 void OnDicomExported(const OrthancApiClient::JsonResponseReadyMessage& message) | 1418 void OnDicomExported(const OrthancApiClient::JsonResponseReadyMessage& message) |
1414 { | 1419 { |
1415 LOG(WARNING) << "DICOM export was successful:" | 1420 LOG(INFO) << "DICOM export was successful:" |
1416 << message.GetJson().toStyledString(); | 1421 << message.GetJson().toStyledString(); |
1417 } | 1422 } |
1418 }; | 1423 }; |
1419 | 1424 |
1420 | 1425 |
1421 class UndoRedoStack : public boost::noncopyable | 1426 class UndoRedoStack : public boost::noncopyable |
1496 } | 1501 } |
1497 } | 1502 } |
1498 }; | 1503 }; |
1499 | 1504 |
1500 | 1505 |
1501 class BitmapCommandBase : public UndoRedoStack::ICommand | 1506 class RadiologyLayerCommand : public UndoRedoStack::ICommand |
1502 { | 1507 { |
1503 private: | 1508 private: |
1504 BitmapStack& stack_; | 1509 RadiologyScene& scene_; |
1505 size_t bitmap_; | 1510 size_t layer_; |
1506 | 1511 |
1507 protected: | 1512 protected: |
1508 virtual void UndoInternal(BitmapStack::Bitmap& bitmap) const = 0; | 1513 virtual void UndoInternal(RadiologyScene::Layer& layer) const = 0; |
1509 | 1514 |
1510 virtual void RedoInternal(BitmapStack::Bitmap& bitmap) const = 0; | 1515 virtual void RedoInternal(RadiologyScene::Layer& layer) const = 0; |
1511 | 1516 |
1512 public: | 1517 public: |
1513 BitmapCommandBase(BitmapStack& stack, | 1518 RadiologyLayerCommand(RadiologyScene& scene, |
1514 size_t bitmap) : | 1519 size_t layer) : |
1515 stack_(stack), | 1520 scene_(scene), |
1516 bitmap_(bitmap) | 1521 layer_(layer) |
1517 { | 1522 { |
1518 } | 1523 } |
1519 | 1524 |
1520 BitmapCommandBase(const BitmapStack::BitmapAccessor& accessor) : | 1525 RadiologyLayerCommand(const RadiologyScene::LayerAccessor& accessor) : |
1521 stack_(accessor.GetStack()), | 1526 scene_(accessor.GetScene()), |
1522 bitmap_(accessor.GetIndex()) | 1527 layer_(accessor.GetIndex()) |
1523 { | 1528 { |
1524 } | 1529 } |
1525 | 1530 |
1526 virtual void Undo() const | 1531 virtual void Undo() const |
1527 { | 1532 { |
1528 BitmapStack::BitmapAccessor accessor(stack_, bitmap_); | 1533 RadiologyScene::LayerAccessor accessor(scene_, layer_); |
1529 | 1534 |
1530 if (accessor.IsValid()) | 1535 if (accessor.IsValid()) |
1531 { | 1536 { |
1532 UndoInternal(accessor.GetBitmap()); | 1537 UndoInternal(accessor.GetLayer()); |
1533 } | 1538 } |
1534 } | 1539 } |
1535 | 1540 |
1536 virtual void Redo() const | 1541 virtual void Redo() const |
1537 { | 1542 { |
1538 BitmapStack::BitmapAccessor accessor(stack_, bitmap_); | 1543 RadiologyScene::LayerAccessor accessor(scene_, layer_); |
1539 | 1544 |
1540 if (accessor.IsValid()) | 1545 if (accessor.IsValid()) |
1541 { | 1546 { |
1542 RedoInternal(accessor.GetBitmap()); | 1547 RedoInternal(accessor.GetLayer()); |
1543 } | 1548 } |
1544 } | 1549 } |
1545 }; | 1550 }; |
1546 | 1551 |
1547 | 1552 |
1548 class RotateBitmapTracker : public IWorldSceneMouseTracker | 1553 class RadiologyLayerRotateTracker : public IWorldSceneMouseTracker |
1549 { | 1554 { |
1550 private: | 1555 private: |
1551 UndoRedoStack& undoRedoStack_; | 1556 UndoRedoStack& undoRedoStack_; |
1552 BitmapStack::BitmapAccessor accessor_; | 1557 RadiologyScene::LayerAccessor accessor_; |
1553 double centerX_; | 1558 double centerX_; |
1554 double centerY_; | 1559 double centerY_; |
1555 double originalAngle_; | 1560 double originalAngle_; |
1556 double clickAngle_; | 1561 double clickAngle_; |
1557 bool roundAngles_; | 1562 bool roundAngles_; |
1558 | 1563 |
1559 bool ComputeAngle(double& angle /* out */, | 1564 bool ComputeAngle(double& angle /* out */, |
1560 double sceneX, | 1565 double sceneX, |
1561 double sceneY) const | 1566 double sceneY) const |
1562 { | 1567 { |
1576 return false; | 1581 return false; |
1577 } | 1582 } |
1578 } | 1583 } |
1579 | 1584 |
1580 | 1585 |
1581 class UndoRedoCommand : public BitmapCommandBase | 1586 class UndoRedoCommand : public RadiologyLayerCommand |
1582 { | 1587 { |
1583 private: | 1588 private: |
1584 double sourceAngle_; | 1589 double sourceAngle_; |
1585 double targetAngle_; | 1590 double targetAngle_; |
1586 | 1591 |
1588 { | 1593 { |
1589 return boost::math::iround(angle * 180.0 / boost::math::constants::pi<double>()); | 1594 return boost::math::iround(angle * 180.0 / boost::math::constants::pi<double>()); |
1590 } | 1595 } |
1591 | 1596 |
1592 protected: | 1597 protected: |
1593 virtual void UndoInternal(BitmapStack::Bitmap& bitmap) const | 1598 virtual void UndoInternal(RadiologyScene::Layer& layer) const |
1594 { | 1599 { |
1595 LOG(INFO) << "Undo - Set angle to " << ToDegrees(sourceAngle_) << " degrees"; | 1600 LOG(INFO) << "Undo - Set angle to " << ToDegrees(sourceAngle_) << " degrees"; |
1596 bitmap.SetAngle(sourceAngle_); | 1601 layer.SetAngle(sourceAngle_); |
1597 } | 1602 } |
1598 | 1603 |
1599 virtual void RedoInternal(BitmapStack::Bitmap& bitmap) const | 1604 virtual void RedoInternal(RadiologyScene::Layer& layer) const |
1600 { | 1605 { |
1601 LOG(INFO) << "Redo - Set angle to " << ToDegrees(sourceAngle_) << " degrees"; | 1606 LOG(INFO) << "Redo - Set angle to " << ToDegrees(sourceAngle_) << " degrees"; |
1602 bitmap.SetAngle(targetAngle_); | 1607 layer.SetAngle(targetAngle_); |
1603 } | 1608 } |
1604 | 1609 |
1605 public: | 1610 public: |
1606 UndoRedoCommand(const RotateBitmapTracker& tracker) : | 1611 UndoRedoCommand(const RadiologyLayerRotateTracker& tracker) : |
1607 BitmapCommandBase(tracker.accessor_), | 1612 RadiologyLayerCommand(tracker.accessor_), |
1608 sourceAngle_(tracker.originalAngle_), | 1613 sourceAngle_(tracker.originalAngle_), |
1609 targetAngle_(tracker.accessor_.GetBitmap().GetAngle()) | 1614 targetAngle_(tracker.accessor_.GetLayer().GetAngle()) |
1610 { | 1615 { |
1611 } | 1616 } |
1612 }; | 1617 }; |
1613 | 1618 |
1614 | 1619 |
1615 public: | 1620 public: |
1616 RotateBitmapTracker(UndoRedoStack& undoRedoStack, | 1621 RadiologyLayerRotateTracker(UndoRedoStack& undoRedoStack, |
1617 BitmapStack& stack, | 1622 RadiologyScene& scene, |
1618 const ViewportGeometry& view, | 1623 const ViewportGeometry& view, |
1619 size_t bitmap, | 1624 size_t layer, |
1620 double x, | 1625 double x, |
1621 double y, | 1626 double y, |
1622 bool roundAngles) : | 1627 bool roundAngles) : |
1623 undoRedoStack_(undoRedoStack), | 1628 undoRedoStack_(undoRedoStack), |
1624 accessor_(stack, bitmap), | 1629 accessor_(scene, layer), |
1625 roundAngles_(roundAngles) | 1630 roundAngles_(roundAngles) |
1626 { | 1631 { |
1627 if (accessor_.IsValid()) | 1632 if (accessor_.IsValid()) |
1628 { | 1633 { |
1629 accessor_.GetBitmap().GetCenter(centerX_, centerY_); | 1634 accessor_.GetLayer().GetCenter(centerX_, centerY_); |
1630 originalAngle_ = accessor_.GetBitmap().GetAngle(); | 1635 originalAngle_ = accessor_.GetLayer().GetAngle(); |
1631 | 1636 |
1632 double sceneX, sceneY; | 1637 double sceneX, sceneY; |
1633 view.MapDisplayToScene(sceneX, sceneY, x, y); | 1638 view.MapDisplayToScene(sceneX, sceneY, x, y); |
1634 | 1639 |
1635 if (!ComputeAngle(clickAngle_, x, y)) | 1640 if (!ComputeAngle(clickAngle_, x, y)) |
1675 if (roundAngles_) | 1680 if (roundAngles_) |
1676 { | 1681 { |
1677 angle = boost::math::round<double>((angle / ROUND_ANGLE) * ROUND_ANGLE); | 1682 angle = boost::math::round<double>((angle / ROUND_ANGLE) * ROUND_ANGLE); |
1678 } | 1683 } |
1679 | 1684 |
1680 accessor_.GetBitmap().SetAngle(angle); | 1685 accessor_.GetLayer().SetAngle(angle); |
1681 } | 1686 } |
1682 } | 1687 } |
1683 }; | 1688 }; |
1684 | 1689 |
1685 | 1690 |
1686 class MoveBitmapTracker : public IWorldSceneMouseTracker | 1691 class RadiologyLayerMoveTracker : public IWorldSceneMouseTracker |
1687 { | 1692 { |
1688 private: | 1693 private: |
1689 UndoRedoStack& undoRedoStack_; | 1694 UndoRedoStack& undoRedoStack_; |
1690 BitmapStack::BitmapAccessor accessor_; | 1695 RadiologyScene::LayerAccessor accessor_; |
1691 double clickX_; | 1696 double clickX_; |
1692 double clickY_; | 1697 double clickY_; |
1693 double panX_; | 1698 double panX_; |
1694 double panY_; | 1699 double panY_; |
1695 bool oneAxis_; | 1700 bool oneAxis_; |
1696 | 1701 |
1697 class UndoRedoCommand : public BitmapCommandBase | 1702 class UndoRedoCommand : public RadiologyLayerCommand |
1698 { | 1703 { |
1699 private: | 1704 private: |
1700 double sourceX_; | 1705 double sourceX_; |
1701 double sourceY_; | 1706 double sourceY_; |
1702 double targetX_; | 1707 double targetX_; |
1703 double targetY_; | 1708 double targetY_; |
1704 | 1709 |
1705 protected: | 1710 protected: |
1706 virtual void UndoInternal(BitmapStack::Bitmap& bitmap) const | 1711 virtual void UndoInternal(RadiologyScene::Layer& layer) const |
1707 { | 1712 { |
1708 bitmap.SetPan(sourceX_, sourceY_); | 1713 layer.SetPan(sourceX_, sourceY_); |
1709 } | 1714 } |
1710 | 1715 |
1711 virtual void RedoInternal(BitmapStack::Bitmap& bitmap) const | 1716 virtual void RedoInternal(RadiologyScene::Layer& layer) const |
1712 { | 1717 { |
1713 bitmap.SetPan(targetX_, targetY_); | 1718 layer.SetPan(targetX_, targetY_); |
1714 } | 1719 } |
1715 | 1720 |
1716 public: | 1721 public: |
1717 UndoRedoCommand(const MoveBitmapTracker& tracker) : | 1722 UndoRedoCommand(const RadiologyLayerMoveTracker& tracker) : |
1718 BitmapCommandBase(tracker.accessor_), | 1723 RadiologyLayerCommand(tracker.accessor_), |
1719 sourceX_(tracker.panX_), | 1724 sourceX_(tracker.panX_), |
1720 sourceY_(tracker.panY_), | 1725 sourceY_(tracker.panY_), |
1721 targetX_(tracker.accessor_.GetBitmap().GetPanX()), | 1726 targetX_(tracker.accessor_.GetLayer().GetPanX()), |
1722 targetY_(tracker.accessor_.GetBitmap().GetPanY()) | 1727 targetY_(tracker.accessor_.GetLayer().GetPanY()) |
1723 { | 1728 { |
1724 } | 1729 } |
1725 }; | 1730 }; |
1726 | 1731 |
1727 | 1732 |
1728 public: | 1733 public: |
1729 MoveBitmapTracker(UndoRedoStack& undoRedoStack, | 1734 RadiologyLayerMoveTracker(UndoRedoStack& undoRedoStack, |
1730 BitmapStack& stack, | 1735 RadiologyScene& scene, |
1731 size_t bitmap, | 1736 size_t layer, |
1732 double x, | 1737 double x, |
1733 double y, | 1738 double y, |
1734 bool oneAxis) : | 1739 bool oneAxis) : |
1735 undoRedoStack_(undoRedoStack), | 1740 undoRedoStack_(undoRedoStack), |
1736 accessor_(stack, bitmap), | 1741 accessor_(scene, layer), |
1737 clickX_(x), | 1742 clickX_(x), |
1738 clickY_(y), | 1743 clickY_(y), |
1739 oneAxis_(oneAxis) | 1744 oneAxis_(oneAxis) |
1740 { | 1745 { |
1741 if (accessor_.IsValid()) | 1746 if (accessor_.IsValid()) |
1742 { | 1747 { |
1743 panX_ = accessor_.GetBitmap().GetPanX(); | 1748 panX_ = accessor_.GetLayer().GetPanX(); |
1744 panY_ = accessor_.GetBitmap().GetPanY(); | 1749 panY_ = accessor_.GetLayer().GetPanY(); |
1745 } | 1750 } |
1746 } | 1751 } |
1747 | 1752 |
1748 virtual bool HasRender() const | 1753 virtual bool HasRender() const |
1749 { | 1754 { |
1776 | 1781 |
1777 if (oneAxis_) | 1782 if (oneAxis_) |
1778 { | 1783 { |
1779 if (fabs(dx) > fabs(dy)) | 1784 if (fabs(dx) > fabs(dy)) |
1780 { | 1785 { |
1781 accessor_.GetBitmap().SetPan(dx + panX_, panY_); | 1786 accessor_.GetLayer().SetPan(dx + panX_, panY_); |
1782 } | 1787 } |
1783 else | 1788 else |
1784 { | 1789 { |
1785 accessor_.GetBitmap().SetPan(panX_, dy + panY_); | 1790 accessor_.GetLayer().SetPan(panX_, dy + panY_); |
1786 } | 1791 } |
1787 } | 1792 } |
1788 else | 1793 else |
1789 { | 1794 { |
1790 accessor_.GetBitmap().SetPan(dx + panX_, dy + panY_); | 1795 accessor_.GetLayer().SetPan(dx + panX_, dy + panY_); |
1791 } | 1796 } |
1792 } | 1797 } |
1793 } | 1798 } |
1794 }; | 1799 }; |
1795 | 1800 |
1796 | 1801 |
1797 class CropBitmapTracker : public IWorldSceneMouseTracker | 1802 class RadiologyLayerCropTracker : public IWorldSceneMouseTracker |
1798 { | 1803 { |
1799 private: | 1804 private: |
1800 UndoRedoStack& undoRedoStack_; | 1805 UndoRedoStack& undoRedoStack_; |
1801 BitmapStack::BitmapAccessor accessor_; | 1806 RadiologyScene::LayerAccessor accessor_; |
1802 BitmapStack::Corner corner_; | 1807 RadiologyScene::Corner corner_; |
1803 unsigned int cropX_; | 1808 unsigned int cropX_; |
1804 unsigned int cropY_; | 1809 unsigned int cropY_; |
1805 unsigned int cropWidth_; | 1810 unsigned int cropWidth_; |
1806 unsigned int cropHeight_; | 1811 unsigned int cropHeight_; |
1807 | 1812 |
1808 class UndoRedoCommand : public BitmapCommandBase | 1813 class UndoRedoCommand : public RadiologyLayerCommand |
1809 { | 1814 { |
1810 private: | 1815 private: |
1811 unsigned int sourceCropX_; | 1816 unsigned int sourceCropX_; |
1812 unsigned int sourceCropY_; | 1817 unsigned int sourceCropY_; |
1813 unsigned int sourceCropWidth_; | 1818 unsigned int sourceCropWidth_; |
1816 unsigned int targetCropY_; | 1821 unsigned int targetCropY_; |
1817 unsigned int targetCropWidth_; | 1822 unsigned int targetCropWidth_; |
1818 unsigned int targetCropHeight_; | 1823 unsigned int targetCropHeight_; |
1819 | 1824 |
1820 protected: | 1825 protected: |
1821 virtual void UndoInternal(BitmapStack::Bitmap& bitmap) const | 1826 virtual void UndoInternal(RadiologyScene::Layer& layer) const |
1822 { | 1827 { |
1823 bitmap.SetCrop(sourceCropX_, sourceCropY_, sourceCropWidth_, sourceCropHeight_); | 1828 layer.SetCrop(sourceCropX_, sourceCropY_, sourceCropWidth_, sourceCropHeight_); |
1824 } | 1829 } |
1825 | 1830 |
1826 virtual void RedoInternal(BitmapStack::Bitmap& bitmap) const | 1831 virtual void RedoInternal(RadiologyScene::Layer& layer) const |
1827 { | 1832 { |
1828 bitmap.SetCrop(targetCropX_, targetCropY_, targetCropWidth_, targetCropHeight_); | 1833 layer.SetCrop(targetCropX_, targetCropY_, targetCropWidth_, targetCropHeight_); |
1829 } | 1834 } |
1830 | 1835 |
1831 public: | 1836 public: |
1832 UndoRedoCommand(const CropBitmapTracker& tracker) : | 1837 UndoRedoCommand(const RadiologyLayerCropTracker& tracker) : |
1833 BitmapCommandBase(tracker.accessor_), | 1838 RadiologyLayerCommand(tracker.accessor_), |
1834 sourceCropX_(tracker.cropX_), | 1839 sourceCropX_(tracker.cropX_), |
1835 sourceCropY_(tracker.cropY_), | 1840 sourceCropY_(tracker.cropY_), |
1836 sourceCropWidth_(tracker.cropWidth_), | 1841 sourceCropWidth_(tracker.cropWidth_), |
1837 sourceCropHeight_(tracker.cropHeight_) | 1842 sourceCropHeight_(tracker.cropHeight_) |
1838 { | 1843 { |
1839 tracker.accessor_.GetBitmap().GetCrop(targetCropX_, targetCropY_, | 1844 tracker.accessor_.GetLayer().GetCrop(targetCropX_, targetCropY_, |
1840 targetCropWidth_, targetCropHeight_); | 1845 targetCropWidth_, targetCropHeight_); |
1841 } | 1846 } |
1842 }; | 1847 }; |
1843 | 1848 |
1844 | 1849 |
1845 public: | 1850 public: |
1846 CropBitmapTracker(UndoRedoStack& undoRedoStack, | 1851 RadiologyLayerCropTracker(UndoRedoStack& undoRedoStack, |
1847 BitmapStack& stack, | 1852 RadiologyScene& scene, |
1848 const ViewportGeometry& view, | 1853 const ViewportGeometry& view, |
1849 size_t bitmap, | 1854 size_t layer, |
1850 double x, | 1855 double x, |
1851 double y, | 1856 double y, |
1852 BitmapStack::Corner corner) : | 1857 RadiologyScene::Corner corner) : |
1853 undoRedoStack_(undoRedoStack), | 1858 undoRedoStack_(undoRedoStack), |
1854 accessor_(stack, bitmap), | 1859 accessor_(scene, layer), |
1855 corner_(corner) | 1860 corner_(corner) |
1856 { | 1861 { |
1857 if (accessor_.IsValid()) | 1862 if (accessor_.IsValid()) |
1858 { | 1863 { |
1859 accessor_.GetBitmap().GetCrop(cropX_, cropY_, cropWidth_, cropHeight_); | 1864 accessor_.GetLayer().GetCrop(cropX_, cropY_, cropWidth_, cropHeight_); |
1860 } | 1865 } |
1861 } | 1866 } |
1862 | 1867 |
1863 virtual bool HasRender() const | 1868 virtual bool HasRender() const |
1864 { | 1869 { |
1886 { | 1891 { |
1887 if (accessor_.IsValid()) | 1892 if (accessor_.IsValid()) |
1888 { | 1893 { |
1889 unsigned int x, y; | 1894 unsigned int x, y; |
1890 | 1895 |
1891 BitmapStack::Bitmap& bitmap = accessor_.GetBitmap(); | 1896 RadiologyScene::Layer& layer = accessor_.GetLayer(); |
1892 if (bitmap.GetPixel(x, y, sceneX, sceneY)) | 1897 if (layer.GetPixel(x, y, sceneX, sceneY)) |
1893 { | 1898 { |
1894 unsigned int targetX, targetWidth; | 1899 unsigned int targetX, targetWidth; |
1895 | 1900 |
1896 if (corner_ == BitmapStack::Corner_TopLeft || | 1901 if (corner_ == RadiologyScene::Corner_TopLeft || |
1897 corner_ == BitmapStack::Corner_BottomLeft) | 1902 corner_ == RadiologyScene::Corner_BottomLeft) |
1898 { | 1903 { |
1899 targetX = std::min(x, cropX_ + cropWidth_); | 1904 targetX = std::min(x, cropX_ + cropWidth_); |
1900 targetWidth = cropX_ + cropWidth_ - targetX; | 1905 targetWidth = cropX_ + cropWidth_ - targetX; |
1901 } | 1906 } |
1902 else | 1907 else |
1905 targetWidth = std::max(x, cropX_) - cropX_; | 1910 targetWidth = std::max(x, cropX_) - cropX_; |
1906 } | 1911 } |
1907 | 1912 |
1908 unsigned int targetY, targetHeight; | 1913 unsigned int targetY, targetHeight; |
1909 | 1914 |
1910 if (corner_ == BitmapStack::Corner_TopLeft || | 1915 if (corner_ == RadiologyScene::Corner_TopLeft || |
1911 corner_ == BitmapStack::Corner_TopRight) | 1916 corner_ == RadiologyScene::Corner_TopRight) |
1912 { | 1917 { |
1913 targetY = std::min(y, cropY_ + cropHeight_); | 1918 targetY = std::min(y, cropY_ + cropHeight_); |
1914 targetHeight = cropY_ + cropHeight_ - targetY; | 1919 targetHeight = cropY_ + cropHeight_ - targetY; |
1915 } | 1920 } |
1916 else | 1921 else |
1917 { | 1922 { |
1918 targetY = cropY_; | 1923 targetY = cropY_; |
1919 targetHeight = std::max(y, cropY_) - cropY_; | 1924 targetHeight = std::max(y, cropY_) - cropY_; |
1920 } | 1925 } |
1921 | 1926 |
1922 bitmap.SetCrop(targetX, targetY, targetWidth, targetHeight); | 1927 layer.SetCrop(targetX, targetY, targetWidth, targetHeight); |
1923 } | 1928 } |
1924 } | 1929 } |
1925 } | 1930 } |
1926 }; | 1931 }; |
1927 | 1932 |
1928 | 1933 |
1929 class ResizeBitmapTracker : public IWorldSceneMouseTracker | 1934 class RadiologyLayerResizeTracker : public IWorldSceneMouseTracker |
1930 { | 1935 { |
1931 private: | 1936 private: |
1932 UndoRedoStack& undoRedoStack_; | 1937 UndoRedoStack& undoRedoStack_; |
1933 BitmapStack::BitmapAccessor accessor_; | 1938 RadiologyScene::LayerAccessor accessor_; |
1934 bool roundScaling_; | 1939 bool roundScaling_; |
1935 double originalSpacingX_; | 1940 double originalSpacingX_; |
1936 double originalSpacingY_; | 1941 double originalSpacingY_; |
1937 double originalPanX_; | 1942 double originalPanX_; |
1938 double originalPanY_; | 1943 double originalPanY_; |
1939 BitmapStack::Corner oppositeCorner_; | 1944 RadiologyScene::Corner oppositeCorner_; |
1940 double oppositeX_; | 1945 double oppositeX_; |
1941 double oppositeY_; | 1946 double oppositeY_; |
1942 double baseScaling_; | 1947 double baseScaling_; |
1943 | 1948 |
1944 static double ComputeDistance(double x1, | 1949 static double ComputeDistance(double x1, |
1945 double y1, | 1950 double y1, |
1946 double x2, | 1951 double x2, |
1947 double y2) | 1952 double y2) |
1949 double dx = x1 - x2; | 1954 double dx = x1 - x2; |
1950 double dy = y1 - y2; | 1955 double dy = y1 - y2; |
1951 return sqrt(dx * dx + dy * dy); | 1956 return sqrt(dx * dx + dy * dy); |
1952 } | 1957 } |
1953 | 1958 |
1954 class UndoRedoCommand : public BitmapCommandBase | 1959 class UndoRedoCommand : public RadiologyLayerCommand |
1955 { | 1960 { |
1956 private: | 1961 private: |
1957 double sourceSpacingX_; | 1962 double sourceSpacingX_; |
1958 double sourceSpacingY_; | 1963 double sourceSpacingY_; |
1959 double sourcePanX_; | 1964 double sourcePanX_; |
1962 double targetSpacingY_; | 1967 double targetSpacingY_; |
1963 double targetPanX_; | 1968 double targetPanX_; |
1964 double targetPanY_; | 1969 double targetPanY_; |
1965 | 1970 |
1966 protected: | 1971 protected: |
1967 virtual void UndoInternal(BitmapStack::Bitmap& bitmap) const | 1972 virtual void UndoInternal(RadiologyScene::Layer& layer) const |
1968 { | 1973 { |
1969 bitmap.SetPixelSpacing(sourceSpacingX_, sourceSpacingY_); | 1974 layer.SetPixelSpacing(sourceSpacingX_, sourceSpacingY_); |
1970 bitmap.SetPan(sourcePanX_, sourcePanY_); | 1975 layer.SetPan(sourcePanX_, sourcePanY_); |
1971 } | 1976 } |
1972 | 1977 |
1973 virtual void RedoInternal(BitmapStack::Bitmap& bitmap) const | 1978 virtual void RedoInternal(RadiologyScene::Layer& layer) const |
1974 { | 1979 { |
1975 bitmap.SetPixelSpacing(targetSpacingX_, targetSpacingY_); | 1980 layer.SetPixelSpacing(targetSpacingX_, targetSpacingY_); |
1976 bitmap.SetPan(targetPanX_, targetPanY_); | 1981 layer.SetPan(targetPanX_, targetPanY_); |
1977 } | 1982 } |
1978 | 1983 |
1979 public: | 1984 public: |
1980 UndoRedoCommand(const ResizeBitmapTracker& tracker) : | 1985 UndoRedoCommand(const RadiologyLayerResizeTracker& tracker) : |
1981 BitmapCommandBase(tracker.accessor_), | 1986 RadiologyLayerCommand(tracker.accessor_), |
1982 sourceSpacingX_(tracker.originalSpacingX_), | 1987 sourceSpacingX_(tracker.originalSpacingX_), |
1983 sourceSpacingY_(tracker.originalSpacingY_), | 1988 sourceSpacingY_(tracker.originalSpacingY_), |
1984 sourcePanX_(tracker.originalPanX_), | 1989 sourcePanX_(tracker.originalPanX_), |
1985 sourcePanY_(tracker.originalPanY_), | 1990 sourcePanY_(tracker.originalPanY_), |
1986 targetSpacingX_(tracker.accessor_.GetBitmap().GetPixelSpacingX()), | 1991 targetSpacingX_(tracker.accessor_.GetLayer().GetPixelSpacingX()), |
1987 targetSpacingY_(tracker.accessor_.GetBitmap().GetPixelSpacingY()), | 1992 targetSpacingY_(tracker.accessor_.GetLayer().GetPixelSpacingY()), |
1988 targetPanX_(tracker.accessor_.GetBitmap().GetPanX()), | 1993 targetPanX_(tracker.accessor_.GetLayer().GetPanX()), |
1989 targetPanY_(tracker.accessor_.GetBitmap().GetPanY()) | 1994 targetPanY_(tracker.accessor_.GetLayer().GetPanY()) |
1990 { | 1995 { |
1991 } | 1996 } |
1992 }; | 1997 }; |
1993 | 1998 |
1994 | 1999 |
1995 public: | 2000 public: |
1996 ResizeBitmapTracker(UndoRedoStack& undoRedoStack, | 2001 RadiologyLayerResizeTracker(UndoRedoStack& undoRedoStack, |
1997 BitmapStack& stack, | 2002 RadiologyScene& scene, |
1998 size_t bitmap, | 2003 size_t layer, |
1999 double x, | 2004 double x, |
2000 double y, | 2005 double y, |
2001 BitmapStack::Corner corner, | 2006 RadiologyScene::Corner corner, |
2002 bool roundScaling) : | 2007 bool roundScaling) : |
2003 undoRedoStack_(undoRedoStack), | 2008 undoRedoStack_(undoRedoStack), |
2004 accessor_(stack, bitmap), | 2009 accessor_(scene, layer), |
2005 roundScaling_(roundScaling) | 2010 roundScaling_(roundScaling) |
2006 { | 2011 { |
2007 if (accessor_.IsValid() && | 2012 if (accessor_.IsValid() && |
2008 accessor_.GetBitmap().IsResizeable()) | 2013 accessor_.GetLayer().IsResizeable()) |
2009 { | 2014 { |
2010 originalSpacingX_ = accessor_.GetBitmap().GetPixelSpacingX(); | 2015 originalSpacingX_ = accessor_.GetLayer().GetPixelSpacingX(); |
2011 originalSpacingY_ = accessor_.GetBitmap().GetPixelSpacingY(); | 2016 originalSpacingY_ = accessor_.GetLayer().GetPixelSpacingY(); |
2012 originalPanX_ = accessor_.GetBitmap().GetPanX(); | 2017 originalPanX_ = accessor_.GetLayer().GetPanX(); |
2013 originalPanY_ = accessor_.GetBitmap().GetPanY(); | 2018 originalPanY_ = accessor_.GetLayer().GetPanY(); |
2014 | 2019 |
2015 switch (corner) | 2020 switch (corner) |
2016 { | 2021 { |
2017 case BitmapStack::Corner_TopLeft: | 2022 case RadiologyScene::Corner_TopLeft: |
2018 oppositeCorner_ = BitmapStack::Corner_BottomRight; | 2023 oppositeCorner_ = RadiologyScene::Corner_BottomRight; |
2019 break; | 2024 break; |
2020 | 2025 |
2021 case BitmapStack::Corner_TopRight: | 2026 case RadiologyScene::Corner_TopRight: |
2022 oppositeCorner_ = BitmapStack::Corner_BottomLeft; | 2027 oppositeCorner_ = RadiologyScene::Corner_BottomLeft; |
2023 break; | 2028 break; |
2024 | 2029 |
2025 case BitmapStack::Corner_BottomLeft: | 2030 case RadiologyScene::Corner_BottomLeft: |
2026 oppositeCorner_ = BitmapStack::Corner_TopRight; | 2031 oppositeCorner_ = RadiologyScene::Corner_TopRight; |
2027 break; | 2032 break; |
2028 | 2033 |
2029 case BitmapStack::Corner_BottomRight: | 2034 case RadiologyScene::Corner_BottomRight: |
2030 oppositeCorner_ = BitmapStack::Corner_TopLeft; | 2035 oppositeCorner_ = RadiologyScene::Corner_TopLeft; |
2031 break; | 2036 break; |
2032 | 2037 |
2033 default: | 2038 default: |
2034 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 2039 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
2035 } | 2040 } |
2036 | 2041 |
2037 accessor_.GetBitmap().GetCorner(oppositeX_, oppositeY_, oppositeCorner_); | 2042 accessor_.GetLayer().GetCorner(oppositeX_, oppositeY_, oppositeCorner_); |
2038 | 2043 |
2039 double d = ComputeDistance(x, y, oppositeX_, oppositeY_); | 2044 double d = ComputeDistance(x, y, oppositeX_, oppositeY_); |
2040 if (d >= std::numeric_limits<float>::epsilon()) | 2045 if (d >= std::numeric_limits<float>::epsilon()) |
2041 { | 2046 { |
2042 baseScaling_ = 1.0 / d; | 2047 baseScaling_ = 1.0 / d; |
2061 } | 2066 } |
2062 | 2067 |
2063 virtual void MouseUp() | 2068 virtual void MouseUp() |
2064 { | 2069 { |
2065 if (accessor_.IsValid() && | 2070 if (accessor_.IsValid() && |
2066 accessor_.GetBitmap().IsResizeable()) | 2071 accessor_.GetLayer().IsResizeable()) |
2067 { | 2072 { |
2068 undoRedoStack_.Add(new UndoRedoCommand(*this)); | 2073 undoRedoStack_.Add(new UndoRedoCommand(*this)); |
2069 } | 2074 } |
2070 } | 2075 } |
2071 | 2076 |
2075 double sceneY) | 2080 double sceneY) |
2076 { | 2081 { |
2077 static const double ROUND_SCALING = 0.1; | 2082 static const double ROUND_SCALING = 0.1; |
2078 | 2083 |
2079 if (accessor_.IsValid() && | 2084 if (accessor_.IsValid() && |
2080 accessor_.GetBitmap().IsResizeable()) | 2085 accessor_.GetLayer().IsResizeable()) |
2081 { | 2086 { |
2082 double scaling = ComputeDistance(oppositeX_, oppositeY_, sceneX, sceneY) * baseScaling_; | 2087 double scaling = ComputeDistance(oppositeX_, oppositeY_, sceneX, sceneY) * baseScaling_; |
2083 | 2088 |
2084 if (roundScaling_) | 2089 if (roundScaling_) |
2085 { | 2090 { |
2086 scaling = boost::math::round<double>((scaling / ROUND_SCALING) * ROUND_SCALING); | 2091 scaling = boost::math::round<double>((scaling / ROUND_SCALING) * ROUND_SCALING); |
2087 } | 2092 } |
2088 | 2093 |
2089 BitmapStack::Bitmap& bitmap = accessor_.GetBitmap(); | 2094 RadiologyScene::Layer& layer = accessor_.GetLayer(); |
2090 bitmap.SetPixelSpacing(scaling * originalSpacingX_, | 2095 layer.SetPixelSpacing(scaling * originalSpacingX_, |
2091 scaling * originalSpacingY_); | 2096 scaling * originalSpacingY_); |
2092 | 2097 |
2093 // Keep the opposite corner at a fixed location | 2098 // Keep the opposite corner at a fixed location |
2094 double ox, oy; | 2099 double ox, oy; |
2095 bitmap.GetCorner(ox, oy, oppositeCorner_); | 2100 layer.GetCorner(ox, oy, oppositeCorner_); |
2096 bitmap.SetPan(bitmap.GetPanX() + oppositeX_ - ox, | 2101 layer.SetPan(layer.GetPanX() + oppositeX_ - ox, |
2097 bitmap.GetPanY() + oppositeY_ - oy); | 2102 layer.GetPanY() + oppositeY_ - oy); |
2098 } | 2103 } |
2099 } | 2104 } |
2100 }; | 2105 }; |
2101 | 2106 |
2102 | 2107 |
2103 class WindowingTracker : public IWorldSceneMouseTracker | 2108 class RadiologyWindowingTracker : public IWorldSceneMouseTracker |
2104 { | 2109 { |
2105 public: | 2110 public: |
2106 enum Action | 2111 enum Action |
2107 { | 2112 { |
2108 Action_IncreaseWidth, | 2113 Action_IncreaseWidth, |
2110 Action_IncreaseCenter, | 2115 Action_IncreaseCenter, |
2111 Action_DecreaseCenter | 2116 Action_DecreaseCenter |
2112 }; | 2117 }; |
2113 | 2118 |
2114 private: | 2119 private: |
2115 UndoRedoStack& undoRedoStack_; | 2120 UndoRedoStack& undoRedoStack_; |
2116 BitmapStack& stack_; | 2121 RadiologyScene& scene_; |
2117 int clickX_; | 2122 int clickX_; |
2118 int clickY_; | 2123 int clickY_; |
2119 Action leftAction_; | 2124 Action leftAction_; |
2120 Action rightAction_; | 2125 Action rightAction_; |
2121 Action upAction_; | 2126 Action upAction_; |
2122 Action downAction_; | 2127 Action downAction_; |
2123 float strength_; | 2128 float strength_; |
2124 float sourceCenter_; | 2129 float sourceCenter_; |
2125 float sourceWidth_; | 2130 float sourceWidth_; |
2126 | 2131 |
2127 static void ComputeAxisEffect(int& deltaCenter, | 2132 static void ComputeAxisEffect(int& deltaCenter, |
2128 int& deltaWidth, | 2133 int& deltaWidth, |
2129 int delta, | 2134 int delta, |
2130 Action actionNegative, | 2135 Action actionNegative, |
2182 | 2187 |
2183 | 2188 |
2184 class UndoRedoCommand : public UndoRedoStack::ICommand | 2189 class UndoRedoCommand : public UndoRedoStack::ICommand |
2185 { | 2190 { |
2186 private: | 2191 private: |
2187 BitmapStack& stack_; | 2192 RadiologyScene& scene_; |
2188 float sourceCenter_; | 2193 float sourceCenter_; |
2189 float sourceWidth_; | 2194 float sourceWidth_; |
2190 float targetCenter_; | 2195 float targetCenter_; |
2191 float targetWidth_; | 2196 float targetWidth_; |
2192 | 2197 |
2193 public: | 2198 public: |
2194 UndoRedoCommand(const WindowingTracker& tracker) : | 2199 UndoRedoCommand(const RadiologyWindowingTracker& tracker) : |
2195 stack_(tracker.stack_), | 2200 scene_(tracker.scene_), |
2196 sourceCenter_(tracker.sourceCenter_), | 2201 sourceCenter_(tracker.sourceCenter_), |
2197 sourceWidth_(tracker.sourceWidth_) | 2202 sourceWidth_(tracker.sourceWidth_) |
2198 { | 2203 { |
2199 stack_.GetWindowingWithDefault(targetCenter_, targetWidth_); | 2204 scene_.GetWindowingWithDefault(targetCenter_, targetWidth_); |
2200 } | 2205 } |
2201 | 2206 |
2202 virtual void Undo() const | 2207 virtual void Undo() const |
2203 { | 2208 { |
2204 stack_.SetWindowing(sourceCenter_, sourceWidth_); | 2209 scene_.SetWindowing(sourceCenter_, sourceWidth_); |
2205 } | 2210 } |
2206 | 2211 |
2207 virtual void Redo() const | 2212 virtual void Redo() const |
2208 { | 2213 { |
2209 stack_.SetWindowing(targetCenter_, targetWidth_); | 2214 scene_.SetWindowing(targetCenter_, targetWidth_); |
2210 } | 2215 } |
2211 }; | 2216 }; |
2212 | 2217 |
2213 | 2218 |
2214 public: | 2219 public: |
2215 WindowingTracker(UndoRedoStack& undoRedoStack, | 2220 RadiologyWindowingTracker(UndoRedoStack& undoRedoStack, |
2216 BitmapStack& stack, | 2221 RadiologyScene& scene, |
2217 int x, | 2222 int x, |
2218 int y, | 2223 int y, |
2219 Action leftAction, | 2224 Action leftAction, |
2220 Action rightAction, | 2225 Action rightAction, |
2221 Action upAction, | 2226 Action upAction, |
2222 Action downAction) : | 2227 Action downAction) : |
2223 undoRedoStack_(undoRedoStack), | 2228 undoRedoStack_(undoRedoStack), |
2224 stack_(stack), | 2229 scene_(scene), |
2225 clickX_(x), | 2230 clickX_(x), |
2226 clickY_(y), | 2231 clickY_(y), |
2227 leftAction_(leftAction), | 2232 leftAction_(leftAction), |
2228 rightAction_(rightAction), | 2233 rightAction_(rightAction), |
2229 upAction_(upAction), | 2234 upAction_(upAction), |
2230 downAction_(downAction) | 2235 downAction_(downAction) |
2231 { | 2236 { |
2232 stack_.GetWindowingWithDefault(sourceCenter_, sourceWidth_); | 2237 scene_.GetWindowingWithDefault(sourceCenter_, sourceWidth_); |
2233 | 2238 |
2234 float minValue, maxValue; | 2239 float minValue, maxValue; |
2235 stack.GetRange(minValue, maxValue); | 2240 scene.GetRange(minValue, maxValue); |
2236 | 2241 |
2237 assert(minValue <= maxValue); | 2242 assert(minValue <= maxValue); |
2238 | 2243 |
2239 float tmp; | 2244 float tmp; |
2240 | 2245 |
2289 ComputeAxisEffect(deltaCenter, deltaWidth, displayX - clickX_, leftAction_, rightAction_); | 2294 ComputeAxisEffect(deltaCenter, deltaWidth, displayX - clickX_, leftAction_, rightAction_); |
2290 ComputeAxisEffect(deltaCenter, deltaWidth, displayY - clickY_, upAction_, downAction_); | 2295 ComputeAxisEffect(deltaCenter, deltaWidth, displayY - clickY_, upAction_, downAction_); |
2291 | 2296 |
2292 float newCenter = sourceCenter_ + (deltaCenter / SCALE * strength_); | 2297 float newCenter = sourceCenter_ + (deltaCenter / SCALE * strength_); |
2293 float newWidth = sourceWidth_ + (deltaWidth / SCALE * strength_); | 2298 float newWidth = sourceWidth_ + (deltaWidth / SCALE * strength_); |
2294 stack_.SetWindowing(newCenter, newWidth); | 2299 scene_.SetWindowing(newCenter, newWidth); |
2295 } | 2300 } |
2296 }; | 2301 }; |
2297 | 2302 |
2298 | 2303 |
2299 class BitmapStackWidget : | 2304 class RadiologyWidget : |
2300 public WorldSceneWidget, | 2305 public WorldSceneWidget, |
2301 public IObserver | 2306 public IObserver |
2302 { | 2307 { |
2303 private: | 2308 private: |
2304 BitmapStack& stack_; | 2309 RadiologyScene& scene_; |
2305 std::auto_ptr<Orthanc::Image> floatBuffer_; | 2310 std::auto_ptr<Orthanc::Image> floatBuffer_; |
2306 std::auto_ptr<CairoSurface> cairoBuffer_; | 2311 std::auto_ptr<CairoSurface> cairoBuffer_; |
2307 bool invert_; | 2312 bool invert_; |
2308 ImageInterpolation interpolation_; | 2313 ImageInterpolation interpolation_; |
2309 bool hasSelection_; | 2314 bool hasSelection_; |
2310 size_t selectedBitmap_; | 2315 size_t selectedLayer_; |
2311 | 2316 |
2312 virtual bool RenderInternal(unsigned int width, | 2317 virtual bool RenderInternal(unsigned int width, |
2313 unsigned int height, | 2318 unsigned int height, |
2314 ImageInterpolation interpolation) | 2319 ImageInterpolation interpolation) |
2315 { | 2320 { |
2316 float windowCenter, windowWidth; | 2321 float windowCenter, windowWidth; |
2317 stack_.GetWindowingWithDefault(windowCenter, windowWidth); | 2322 scene_.GetWindowingWithDefault(windowCenter, windowWidth); |
2318 | 2323 |
2319 float x0 = windowCenter - windowWidth / 2.0f; | 2324 float x0 = windowCenter - windowWidth / 2.0f; |
2320 float x1 = windowCenter + windowWidth / 2.0f; | 2325 float x1 = windowCenter + windowWidth / 2.0f; |
2321 | 2326 |
2322 if (windowWidth <= 0.001f) // Avoid division by zero at (*) | 2327 if (windowWidth <= 0.001f) // Avoid division by zero at (*) |
2337 cairoBuffer_->GetHeight() != height) | 2342 cairoBuffer_->GetHeight() != height) |
2338 { | 2343 { |
2339 cairoBuffer_.reset(new CairoSurface(width, height)); | 2344 cairoBuffer_.reset(new CairoSurface(width, height)); |
2340 } | 2345 } |
2341 | 2346 |
2342 stack_.Render(*floatBuffer_, GetView().GetMatrix(), interpolation); | 2347 scene_.Render(*floatBuffer_, GetView().GetMatrix(), interpolation); |
2343 | 2348 |
2344 // Conversion from Float32 to BGRA32 (cairo). Very similar to | 2349 // Conversion from Float32 to BGRA32 (cairo). Very similar to |
2345 // GrayscaleFrameRenderer => TODO MERGE? | 2350 // GrayscaleFrameRenderer => TODO MERGE? |
2346 | 2351 |
2347 Orthanc::ImageAccessor target; | 2352 Orthanc::ImageAccessor target; |
2388 } | 2393 } |
2389 | 2394 |
2390 protected: | 2395 protected: |
2391 virtual Extent2D GetSceneExtent() | 2396 virtual Extent2D GetSceneExtent() |
2392 { | 2397 { |
2393 return stack_.GetSceneExtent(); | 2398 return scene_.GetSceneExtent(); |
2394 } | 2399 } |
2395 | 2400 |
2396 virtual bool RenderScene(CairoContext& context, | 2401 virtual bool RenderScene(CairoContext& context, |
2397 const ViewportGeometry& view) | 2402 const ViewportGeometry& view) |
2398 { | 2403 { |
2414 cairo_paint(cr); | 2419 cairo_paint(cr); |
2415 } | 2420 } |
2416 | 2421 |
2417 if (hasSelection_) | 2422 if (hasSelection_) |
2418 { | 2423 { |
2419 stack_.DrawBorder(context, selectedBitmap_, view.GetZoom()); | 2424 scene_.DrawBorder(context, selectedLayer_, view.GetZoom()); |
2420 } | 2425 } |
2421 | 2426 |
2422 return true; | 2427 return true; |
2423 } | 2428 } |
2424 | 2429 |
2425 public: | 2430 public: |
2426 BitmapStackWidget(MessageBroker& broker, | 2431 RadiologyWidget(MessageBroker& broker, |
2427 BitmapStack& stack, | 2432 RadiologyScene& scene, |
2428 const std::string& name) : | 2433 const std::string& name) : |
2429 WorldSceneWidget(name), | 2434 WorldSceneWidget(name), |
2430 IObserver(broker), | 2435 IObserver(broker), |
2431 stack_(stack), | 2436 scene_(scene), |
2432 invert_(false), | 2437 invert_(false), |
2433 interpolation_(ImageInterpolation_Nearest), | 2438 interpolation_(ImageInterpolation_Nearest), |
2434 hasSelection_(false), | 2439 hasSelection_(false), |
2435 selectedBitmap_(0) // Dummy initialization | 2440 selectedLayer_(0) // Dummy initialization |
2436 { | 2441 { |
2437 stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::GeometryChangedMessage>(*this, &BitmapStackWidget::OnGeometryChanged)); | 2442 scene.RegisterObserverCallback( |
2438 stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::ContentChangedMessage>(*this, &BitmapStackWidget::OnContentChanged)); | 2443 new Callable<RadiologyWidget, RadiologyScene::GeometryChangedMessage> |
2439 } | 2444 (*this, &RadiologyWidget::OnGeometryChanged)); |
2440 | 2445 |
2441 BitmapStack& GetStack() const | 2446 scene.RegisterObserverCallback( |
2442 { | 2447 new Callable<RadiologyWidget, RadiologyScene::ContentChangedMessage> |
2443 return stack_; | 2448 (*this, &RadiologyWidget::OnContentChanged)); |
2449 } | |
2450 | |
2451 RadiologyScene& GetScene() const | |
2452 { | |
2453 return scene_; | |
2444 } | 2454 } |
2445 | 2455 |
2446 void Unselect() | 2456 void Unselect() |
2447 { | 2457 { |
2448 hasSelection_ = false; | 2458 hasSelection_ = false; |
2449 } | 2459 } |
2450 | 2460 |
2451 void Select(size_t bitmap) | 2461 void Select(size_t layer) |
2452 { | 2462 { |
2453 hasSelection_ = true; | 2463 hasSelection_ = true; |
2454 selectedBitmap_ = bitmap; | 2464 selectedLayer_ = layer; |
2455 } | 2465 } |
2456 | 2466 |
2457 bool LookupSelectedBitmap(size_t& bitmap) | 2467 bool LookupSelectedLayer(size_t& layer) |
2458 { | 2468 { |
2459 if (hasSelection_) | 2469 if (hasSelection_) |
2460 { | 2470 { |
2461 bitmap = selectedBitmap_; | 2471 layer = selectedLayer_; |
2462 return true; | 2472 return true; |
2463 } | 2473 } |
2464 else | 2474 else |
2465 { | 2475 { |
2466 return false; | 2476 return false; |
2467 } | 2477 } |
2468 } | 2478 } |
2469 | 2479 |
2470 void OnGeometryChanged(const BitmapStack::GeometryChangedMessage& message) | 2480 void OnGeometryChanged(const RadiologyScene::GeometryChangedMessage& message) |
2471 { | 2481 { |
2472 LOG(INFO) << "Geometry has changed"; | 2482 LOG(INFO) << "Geometry has changed"; |
2473 FitContent(); | 2483 FitContent(); |
2474 } | 2484 } |
2475 | 2485 |
2476 void OnContentChanged(const BitmapStack::ContentChangedMessage& message) | 2486 void OnContentChanged(const RadiologyScene::ContentChangedMessage& message) |
2477 { | 2487 { |
2478 LOG(INFO) << "Content has changed"; | 2488 LOG(INFO) << "Content has changed"; |
2479 NotifyContentChanged(); | 2489 NotifyContentChanged(); |
2480 } | 2490 } |
2481 | 2491 |
2513 return interpolation_; | 2523 return interpolation_; |
2514 } | 2524 } |
2515 }; | 2525 }; |
2516 | 2526 |
2517 | 2527 |
2518 class BitmapStackInteractor : | 2528 namespace Samples |
2519 public IWorldSceneInteractor, | |
2520 public IObserver | |
2521 { | 2529 { |
2522 private: | 2530 class RadiologyEditorInteractor : |
2523 enum Tool | 2531 public IWorldSceneInteractor, |
2524 { | 2532 public IObserver |
2525 Tool_Move, | 2533 { |
2526 Tool_Rotate, | 2534 private: |
2527 Tool_Crop, | 2535 enum Tool |
2528 Tool_Resize, | 2536 { |
2529 Tool_Windowing | 2537 Tool_Move, |
2530 }; | 2538 Tool_Rotate, |
2531 | 2539 Tool_Crop, |
2532 | 2540 Tool_Resize, |
2533 UndoRedoStack undoRedoStack_; | 2541 Tool_Windowing |
2534 Tool tool_; | 2542 }; |
2535 | 2543 |
2536 | 2544 |
2537 static double GetHandleSize() | 2545 UndoRedoStack undoRedoStack_; |
2538 { | 2546 Tool tool_; |
2539 return 10.0; | 2547 |
2540 } | 2548 |
2549 static double GetHandleSize() | |
2550 { | |
2551 return 10.0; | |
2552 } | |
2541 | 2553 |
2542 | 2554 |
2543 public: | 2555 public: |
2544 BitmapStackInteractor(MessageBroker& broker) : | 2556 RadiologyEditorInteractor(MessageBroker& broker) : |
2545 IObserver(broker), | 2557 IObserver(broker), |
2546 tool_(Tool_Move) | 2558 tool_(Tool_Move) |
2547 { | 2559 { |
2548 } | 2560 } |
2549 | 2561 |
2550 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& worldWidget, | 2562 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& worldWidget, |
2551 const ViewportGeometry& view, | 2563 const ViewportGeometry& view, |
2552 MouseButton button, | 2564 MouseButton button, |
2553 KeyboardModifiers modifiers, | 2565 KeyboardModifiers modifiers, |
2554 int viewportX, | 2566 int viewportX, |
2555 int viewportY, | 2567 int viewportY, |
2556 double x, | 2568 double x, |
2557 double y, | 2569 double y, |
2558 IStatusBar* statusBar) | 2570 IStatusBar* statusBar) |
2559 { | 2571 { |
2560 BitmapStackWidget& widget = dynamic_cast<BitmapStackWidget&>(worldWidget); | 2572 RadiologyWidget& widget = dynamic_cast<RadiologyWidget&>(worldWidget); |
2561 | 2573 |
2562 if (button == MouseButton_Left) | 2574 if (button == MouseButton_Left) |
2563 { | 2575 { |
2564 size_t selected; | 2576 size_t selected; |
2565 | 2577 |
2566 if (tool_ == Tool_Windowing) | 2578 if (tool_ == Tool_Windowing) |
2567 { | 2579 { |
2568 return new WindowingTracker(undoRedoStack_, widget.GetStack(), | 2580 return new RadiologyWindowingTracker(undoRedoStack_, widget.GetScene(), |
2569 viewportX, viewportY, | 2581 viewportX, viewportY, |
2570 WindowingTracker::Action_DecreaseWidth, | 2582 RadiologyWindowingTracker::Action_DecreaseWidth, |
2571 WindowingTracker::Action_IncreaseWidth, | 2583 RadiologyWindowingTracker::Action_IncreaseWidth, |
2572 WindowingTracker::Action_DecreaseCenter, | 2584 RadiologyWindowingTracker::Action_DecreaseCenter, |
2573 WindowingTracker::Action_IncreaseCenter); | 2585 RadiologyWindowingTracker::Action_IncreaseCenter); |
2574 } | 2586 } |
2575 else if (!widget.LookupSelectedBitmap(selected)) | 2587 else if (!widget.LookupSelectedLayer(selected)) |
2576 { | 2588 { |
2577 // No bitmap is currently selected | 2589 // No layer is currently selected |
2578 size_t bitmap; | 2590 size_t layer; |
2579 if (widget.GetStack().LookupBitmap(bitmap, x, y)) | 2591 if (widget.GetScene().LookupLayer(layer, x, y)) |
2580 { | |
2581 widget.Select(bitmap); | |
2582 } | |
2583 | |
2584 return NULL; | |
2585 } | |
2586 else if (tool_ == Tool_Crop || | |
2587 tool_ == Tool_Resize) | |
2588 { | |
2589 BitmapStack::BitmapAccessor accessor(widget.GetStack(), selected); | |
2590 BitmapStack::Corner corner; | |
2591 if (accessor.GetBitmap().LookupCorner(corner, x, y, view.GetZoom(), GetHandleSize())) | |
2592 { | |
2593 switch (tool_) | |
2594 { | 2592 { |
2595 case Tool_Crop: | 2593 widget.Select(layer); |
2596 return new CropBitmapTracker(undoRedoStack_, widget.GetStack(), view, selected, x, y, corner); | |
2597 | |
2598 case Tool_Resize: | |
2599 return new ResizeBitmapTracker(undoRedoStack_, widget.GetStack(), selected, x, y, corner, | |
2600 (modifiers & KeyboardModifiers_Shift)); | |
2601 | |
2602 default: | |
2603 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
2604 } | 2594 } |
2595 | |
2596 return NULL; | |
2597 } | |
2598 else if (tool_ == Tool_Crop || | |
2599 tool_ == Tool_Resize) | |
2600 { | |
2601 RadiologyScene::LayerAccessor accessor(widget.GetScene(), selected); | |
2602 RadiologyScene::Corner corner; | |
2603 if (accessor.GetLayer().LookupCorner(corner, x, y, view.GetZoom(), GetHandleSize())) | |
2604 { | |
2605 switch (tool_) | |
2606 { | |
2607 case Tool_Crop: | |
2608 return new RadiologyLayerCropTracker(undoRedoStack_, widget.GetScene(), view, selected, x, y, corner); | |
2609 | |
2610 case Tool_Resize: | |
2611 return new RadiologyLayerResizeTracker(undoRedoStack_, widget.GetScene(), selected, x, y, corner, | |
2612 (modifiers & KeyboardModifiers_Shift)); | |
2613 | |
2614 default: | |
2615 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
2616 } | |
2617 } | |
2618 else | |
2619 { | |
2620 size_t layer; | |
2621 | |
2622 if (widget.GetScene().LookupLayer(layer, x, y)) | |
2623 { | |
2624 widget.Select(layer); | |
2625 } | |
2626 else | |
2627 { | |
2628 widget.Unselect(); | |
2629 } | |
2630 | |
2631 return NULL; | |
2632 } | |
2605 } | 2633 } |
2606 else | 2634 else |
2607 { | 2635 { |
2608 size_t bitmap; | 2636 size_t layer; |
2609 | 2637 |
2610 if (widget.GetStack().LookupBitmap(bitmap, x, y)) | 2638 if (widget.GetScene().LookupLayer(layer, x, y)) |
2611 { | 2639 { |
2612 widget.Select(bitmap); | 2640 if (layer == selected) |
2641 { | |
2642 switch (tool_) | |
2643 { | |
2644 case Tool_Move: | |
2645 return new RadiologyLayerMoveTracker(undoRedoStack_, widget.GetScene(), layer, x, y, | |
2646 (modifiers & KeyboardModifiers_Shift)); | |
2647 | |
2648 case Tool_Rotate: | |
2649 return new RadiologyLayerRotateTracker(undoRedoStack_, widget.GetScene(), view, layer, x, y, | |
2650 (modifiers & KeyboardModifiers_Shift)); | |
2651 | |
2652 default: | |
2653 break; | |
2654 } | |
2655 | |
2656 return NULL; | |
2657 } | |
2658 else | |
2659 { | |
2660 widget.Select(layer); | |
2661 return NULL; | |
2662 } | |
2613 } | 2663 } |
2614 else | 2664 else |
2615 { | 2665 { |
2616 widget.Unselect(); | 2666 widget.Unselect(); |
2617 } | |
2618 | |
2619 return NULL; | |
2620 } | |
2621 } | |
2622 else | |
2623 { | |
2624 size_t bitmap; | |
2625 | |
2626 if (widget.GetStack().LookupBitmap(bitmap, x, y)) | |
2627 { | |
2628 if (bitmap == selected) | |
2629 { | |
2630 switch (tool_) | |
2631 { | |
2632 case Tool_Move: | |
2633 return new MoveBitmapTracker(undoRedoStack_, widget.GetStack(), bitmap, x, y, | |
2634 (modifiers & KeyboardModifiers_Shift)); | |
2635 | |
2636 case Tool_Rotate: | |
2637 return new RotateBitmapTracker(undoRedoStack_, widget.GetStack(), view, bitmap, x, y, | |
2638 (modifiers & KeyboardModifiers_Shift)); | |
2639 | |
2640 default: | |
2641 break; | |
2642 } | |
2643 | |
2644 return NULL; | 2667 return NULL; |
2645 } | 2668 } |
2646 else | 2669 } |
2670 } | |
2671 else | |
2672 { | |
2673 return NULL; | |
2674 } | |
2675 } | |
2676 | |
2677 virtual void MouseOver(CairoContext& context, | |
2678 WorldSceneWidget& worldWidget, | |
2679 const ViewportGeometry& view, | |
2680 double x, | |
2681 double y, | |
2682 IStatusBar* statusBar) | |
2683 { | |
2684 RadiologyWidget& widget = dynamic_cast<RadiologyWidget&>(worldWidget); | |
2685 | |
2686 #if 0 | |
2687 if (statusBar != NULL) | |
2688 { | |
2689 char buf[64]; | |
2690 sprintf(buf, "X = %.02f Y = %.02f (in cm)", x / 10.0, y / 10.0); | |
2691 statusBar->SetMessage(buf); | |
2692 } | |
2693 #endif | |
2694 | |
2695 size_t selected; | |
2696 | |
2697 if (widget.LookupSelectedLayer(selected) && | |
2698 (tool_ == Tool_Crop || | |
2699 tool_ == Tool_Resize)) | |
2700 { | |
2701 RadiologyScene::LayerAccessor accessor(widget.GetScene(), selected); | |
2702 | |
2703 RadiologyScene::Corner corner; | |
2704 if (accessor.GetLayer().LookupCorner(corner, x, y, view.GetZoom(), GetHandleSize())) | |
2705 { | |
2706 accessor.GetLayer().GetCorner(x, y, corner); | |
2707 | |
2708 double z = 1.0 / view.GetZoom(); | |
2709 | |
2710 context.SetSourceColor(255, 0, 0); | |
2711 cairo_t* cr = context.GetObject(); | |
2712 cairo_set_line_width(cr, 2.0 * z); | |
2713 cairo_move_to(cr, x - GetHandleSize() * z, y - GetHandleSize() * z); | |
2714 cairo_line_to(cr, x + GetHandleSize() * z, y - GetHandleSize() * z); | |
2715 cairo_line_to(cr, x + GetHandleSize() * z, y + GetHandleSize() * z); | |
2716 cairo_line_to(cr, x - GetHandleSize() * z, y + GetHandleSize() * z); | |
2717 cairo_line_to(cr, x - GetHandleSize() * z, y - GetHandleSize() * z); | |
2718 cairo_stroke(cr); | |
2719 } | |
2720 } | |
2721 } | |
2722 | |
2723 virtual void MouseWheel(WorldSceneWidget& widget, | |
2724 MouseWheelDirection direction, | |
2725 KeyboardModifiers modifiers, | |
2726 IStatusBar* statusBar) | |
2727 { | |
2728 } | |
2729 | |
2730 virtual void KeyPressed(WorldSceneWidget& worldWidget, | |
2731 KeyboardKeys key, | |
2732 char keyChar, | |
2733 KeyboardModifiers modifiers, | |
2734 IStatusBar* statusBar) | |
2735 { | |
2736 RadiologyWidget& widget = dynamic_cast<RadiologyWidget&>(worldWidget); | |
2737 | |
2738 switch (keyChar) | |
2739 { | |
2740 case 'a': | |
2741 widget.FitContent(); | |
2742 break; | |
2743 | |
2744 case 'c': | |
2745 tool_ = Tool_Crop; | |
2746 break; | |
2747 | |
2748 case 'e': | |
2749 { | |
2750 Orthanc::DicomMap tags; | |
2751 | |
2752 // Minimal set of tags to generate a valid CR image | |
2753 tags.SetValue(Orthanc::DICOM_TAG_ACCESSION_NUMBER, "NOPE", false); | |
2754 tags.SetValue(Orthanc::DICOM_TAG_BODY_PART_EXAMINED, "PELVIS", false); | |
2755 tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "1", false); | |
2756 //tags.SetValue(Orthanc::DICOM_TAG_LATERALITY, "", false); | |
2757 tags.SetValue(Orthanc::DICOM_TAG_MANUFACTURER, "OSIMIS", false); | |
2758 tags.SetValue(Orthanc::DICOM_TAG_MODALITY, "CR", false); | |
2759 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_BIRTH_DATE, "20000101", false); | |
2760 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_ID, "hello", false); | |
2761 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_NAME, "HELLO^WORLD", false); | |
2762 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_ORIENTATION, "", false); | |
2763 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_SEX, "M", false); | |
2764 tags.SetValue(Orthanc::DICOM_TAG_REFERRING_PHYSICIAN_NAME, "HOUSE^MD", false); | |
2765 tags.SetValue(Orthanc::DICOM_TAG_SERIES_NUMBER, "1", false); | |
2766 tags.SetValue(Orthanc::DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.1", false); | |
2767 tags.SetValue(Orthanc::DICOM_TAG_STUDY_ID, "STUDY", false); | |
2768 tags.SetValue(Orthanc::DICOM_TAG_VIEW_POSITION, "", false); | |
2769 | |
2770 widget.GetScene().Export(tags, 0.1, 0.1, widget.IsInverted(), | |
2771 widget.GetInterpolation(), EXPORT_USING_PAM); | |
2772 break; | |
2773 } | |
2774 | |
2775 case 'i': | |
2776 widget.SwitchInvert(); | |
2777 break; | |
2778 | |
2779 case 'm': | |
2780 tool_ = Tool_Move; | |
2781 break; | |
2782 | |
2783 case 'n': | |
2784 { | |
2785 switch (widget.GetInterpolation()) | |
2647 { | 2786 { |
2648 widget.Select(bitmap); | 2787 case ImageInterpolation_Nearest: |
2649 return NULL; | 2788 LOG(INFO) << "Switching to bilinear interpolation"; |
2789 widget.SetInterpolation(ImageInterpolation_Bilinear); | |
2790 break; | |
2791 | |
2792 case ImageInterpolation_Bilinear: | |
2793 LOG(INFO) << "Switching to nearest neighbor interpolation"; | |
2794 widget.SetInterpolation(ImageInterpolation_Nearest); | |
2795 break; | |
2796 | |
2797 default: | |
2798 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
2650 } | 2799 } |
2651 } | |
2652 else | |
2653 { | |
2654 widget.Unselect(); | |
2655 return NULL; | |
2656 } | |
2657 } | |
2658 } | |
2659 else | |
2660 { | |
2661 return NULL; | |
2662 } | |
2663 } | |
2664 | |
2665 virtual void MouseOver(CairoContext& context, | |
2666 WorldSceneWidget& worldWidget, | |
2667 const ViewportGeometry& view, | |
2668 double x, | |
2669 double y, | |
2670 IStatusBar* statusBar) | |
2671 { | |
2672 BitmapStackWidget& widget = dynamic_cast<BitmapStackWidget&>(worldWidget); | |
2673 | |
2674 #if 0 | |
2675 if (statusBar != NULL) | |
2676 { | |
2677 char buf[64]; | |
2678 sprintf(buf, "X = %.02f Y = %.02f (in cm)", x / 10.0, y / 10.0); | |
2679 statusBar->SetMessage(buf); | |
2680 } | |
2681 #endif | |
2682 | |
2683 size_t selected; | |
2684 | |
2685 if (widget.LookupSelectedBitmap(selected) && | |
2686 (tool_ == Tool_Crop || | |
2687 tool_ == Tool_Resize)) | |
2688 { | |
2689 BitmapStack::BitmapAccessor accessor(widget.GetStack(), selected); | |
2690 | |
2691 BitmapStack::Corner corner; | |
2692 if (accessor.GetBitmap().LookupCorner(corner, x, y, view.GetZoom(), GetHandleSize())) | |
2693 { | |
2694 accessor.GetBitmap().GetCorner(x, y, corner); | |
2695 | 2800 |
2696 double z = 1.0 / view.GetZoom(); | 2801 break; |
2697 | 2802 } |
2698 context.SetSourceColor(255, 0, 0); | 2803 |
2699 cairo_t* cr = context.GetObject(); | 2804 case 'r': |
2700 cairo_set_line_width(cr, 2.0 * z); | 2805 tool_ = Tool_Rotate; |
2701 cairo_move_to(cr, x - GetHandleSize() * z, y - GetHandleSize() * z); | 2806 break; |
2702 cairo_line_to(cr, x + GetHandleSize() * z, y - GetHandleSize() * z); | 2807 |
2703 cairo_line_to(cr, x + GetHandleSize() * z, y + GetHandleSize() * z); | 2808 case 's': |
2704 cairo_line_to(cr, x - GetHandleSize() * z, y + GetHandleSize() * z); | 2809 tool_ = Tool_Resize; |
2705 cairo_line_to(cr, x - GetHandleSize() * z, y - GetHandleSize() * z); | 2810 break; |
2706 cairo_stroke(cr); | 2811 |
2707 } | 2812 case 'w': |
2708 } | 2813 tool_ = Tool_Windowing; |
2709 } | 2814 break; |
2710 | 2815 |
2711 virtual void MouseWheel(WorldSceneWidget& widget, | 2816 case 'y': |
2712 MouseWheelDirection direction, | 2817 if (modifiers & KeyboardModifiers_Control) |
2713 KeyboardModifiers modifiers, | 2818 { |
2714 IStatusBar* statusBar) | 2819 undoRedoStack_.Redo(); |
2715 { | 2820 widget.NotifyContentChanged(); |
2716 } | 2821 } |
2717 | 2822 break; |
2718 virtual void KeyPressed(WorldSceneWidget& worldWidget, | 2823 |
2719 KeyboardKeys key, | 2824 case 'z': |
2720 char keyChar, | 2825 if (modifiers & KeyboardModifiers_Control) |
2721 KeyboardModifiers modifiers, | 2826 { |
2722 IStatusBar* statusBar) | 2827 undoRedoStack_.Undo(); |
2723 { | 2828 widget.NotifyContentChanged(); |
2724 BitmapStackWidget& widget = dynamic_cast<BitmapStackWidget&>(worldWidget); | 2829 } |
2725 | 2830 break; |
2726 switch (keyChar) | 2831 |
2727 { | 2832 default: |
2728 case 'a': | 2833 break; |
2729 widget.FitContent(); | 2834 } |
2730 break; | 2835 } |
2731 | 2836 }; |
2732 case 'c': | |
2733 tool_ = Tool_Crop; | |
2734 break; | |
2735 | |
2736 case 'e': | |
2737 { | |
2738 Orthanc::DicomMap tags; | |
2739 | |
2740 // Minimal set of tags to generate a valid CR image | |
2741 tags.SetValue(Orthanc::DICOM_TAG_ACCESSION_NUMBER, "NOPE", false); | |
2742 tags.SetValue(Orthanc::DICOM_TAG_BODY_PART_EXAMINED, "PELVIS", false); | |
2743 tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "1", false); | |
2744 //tags.SetValue(Orthanc::DICOM_TAG_LATERALITY, "", false); | |
2745 tags.SetValue(Orthanc::DICOM_TAG_MANUFACTURER, "OSIMIS", false); | |
2746 tags.SetValue(Orthanc::DICOM_TAG_MODALITY, "CR", false); | |
2747 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_BIRTH_DATE, "20000101", false); | |
2748 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_ID, "hello", false); | |
2749 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_NAME, "HELLO^WORLD", false); | |
2750 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_ORIENTATION, "", false); | |
2751 tags.SetValue(Orthanc::DICOM_TAG_PATIENT_SEX, "M", false); | |
2752 tags.SetValue(Orthanc::DICOM_TAG_REFERRING_PHYSICIAN_NAME, "HOUSE^MD", false); | |
2753 tags.SetValue(Orthanc::DICOM_TAG_SERIES_NUMBER, "1", false); | |
2754 tags.SetValue(Orthanc::DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.1", false); | |
2755 tags.SetValue(Orthanc::DICOM_TAG_STUDY_ID, "STUDY", false); | |
2756 tags.SetValue(Orthanc::DICOM_TAG_VIEW_POSITION, "", false); | |
2757 | |
2758 widget.GetStack().Export(tags, 0.1, 0.1, widget.IsInverted(), widget.GetInterpolation()); | |
2759 break; | |
2760 } | |
2761 | |
2762 case 'i': | |
2763 widget.SwitchInvert(); | |
2764 break; | |
2765 | |
2766 case 'm': | |
2767 tool_ = Tool_Move; | |
2768 break; | |
2769 | |
2770 case 'n': | |
2771 { | |
2772 switch (widget.GetInterpolation()) | |
2773 { | |
2774 case ImageInterpolation_Nearest: | |
2775 LOG(INFO) << "Switching to bilinear interpolation"; | |
2776 widget.SetInterpolation(ImageInterpolation_Bilinear); | |
2777 break; | |
2778 | |
2779 case ImageInterpolation_Bilinear: | |
2780 LOG(INFO) << "Switching to nearest neighbor interpolation"; | |
2781 widget.SetInterpolation(ImageInterpolation_Nearest); | |
2782 break; | |
2783 | |
2784 default: | |
2785 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
2786 } | |
2787 | |
2788 break; | |
2789 } | |
2790 | |
2791 case 'r': | |
2792 tool_ = Tool_Rotate; | |
2793 break; | |
2794 | |
2795 case 's': | |
2796 tool_ = Tool_Resize; | |
2797 break; | |
2798 | |
2799 case 'w': | |
2800 tool_ = Tool_Windowing; | |
2801 break; | |
2802 | |
2803 case 'y': | |
2804 if (modifiers & KeyboardModifiers_Control) | |
2805 { | |
2806 undoRedoStack_.Redo(); | |
2807 widget.NotifyContentChanged(); | |
2808 } | |
2809 break; | |
2810 | |
2811 case 'z': | |
2812 if (modifiers & KeyboardModifiers_Control) | |
2813 { | |
2814 undoRedoStack_.Undo(); | |
2815 widget.NotifyContentChanged(); | |
2816 } | |
2817 break; | |
2818 | |
2819 default: | |
2820 break; | |
2821 } | |
2822 } | |
2823 }; | |
2824 | 2837 |
2825 | 2838 |
2826 | 2839 |
2827 namespace Samples | |
2828 { | |
2829 class SingleFrameEditorApplication : | 2840 class SingleFrameEditorApplication : |
2830 public SampleSingleCanvasApplicationBase, | 2841 public SampleSingleCanvasApplicationBase, |
2831 public IObserver | 2842 public IObserver |
2832 { | 2843 { |
2833 private: | 2844 private: |
2834 std::auto_ptr<OrthancApiClient> orthancApiClient_; | 2845 std::auto_ptr<OrthancApiClient> orthancApiClient_; |
2835 std::auto_ptr<BitmapStack> stack_; | 2846 std::auto_ptr<RadiologyScene> scene_; |
2836 BitmapStackInteractor interactor_; | 2847 RadiologyEditorInteractor interactor_; |
2837 | 2848 |
2838 public: | 2849 public: |
2839 SingleFrameEditorApplication(MessageBroker& broker) : | 2850 SingleFrameEditorApplication(MessageBroker& broker) : |
2840 IObserver(broker), | 2851 IObserver(broker), |
2841 interactor_(broker) | 2852 interactor_(broker) |
2874 statusBar.SetMessage("Use the key \"f\" to switch full screen"); | 2885 statusBar.SetMessage("Use the key \"f\" to switch full screen"); |
2875 statusBar.SetMessage("Use the key \"i\" to invert contrast"); | 2886 statusBar.SetMessage("Use the key \"i\" to invert contrast"); |
2876 statusBar.SetMessage("Use the key \"m\" to move objects"); | 2887 statusBar.SetMessage("Use the key \"m\" to move objects"); |
2877 statusBar.SetMessage("Use the key \"n\" to switch between nearest neighbor and bilinear interpolation"); | 2888 statusBar.SetMessage("Use the key \"n\" to switch between nearest neighbor and bilinear interpolation"); |
2878 statusBar.SetMessage("Use the key \"r\" to rotate objects"); | 2889 statusBar.SetMessage("Use the key \"r\" to rotate objects"); |
2879 statusBar.SetMessage("Use the key \"s\" to resize objects (not applicable to DICOM bitmaps)"); | 2890 statusBar.SetMessage("Use the key \"s\" to resize objects (not applicable to DICOM layers)"); |
2880 statusBar.SetMessage("Use the key \"w\" to change windowing"); | 2891 statusBar.SetMessage("Use the key \"w\" to change windowing"); |
2881 | 2892 |
2882 statusBar.SetMessage("Use the key \"ctrl-z\" to undo action"); | 2893 statusBar.SetMessage("Use the key \"ctrl-z\" to undo action"); |
2883 statusBar.SetMessage("Use the key \"ctrl-y\" to redo action"); | 2894 statusBar.SetMessage("Use the key \"ctrl-y\" to redo action"); |
2884 | 2895 |
2894 orthancApiClient_.reset(new OrthancApiClient(GetBroker(), context_->GetWebService())); | 2905 orthancApiClient_.reset(new OrthancApiClient(GetBroker(), context_->GetWebService())); |
2895 | 2906 |
2896 Orthanc::FontRegistry fonts; | 2907 Orthanc::FontRegistry fonts; |
2897 fonts.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16); | 2908 fonts.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16); |
2898 | 2909 |
2899 stack_.reset(new BitmapStack(GetBroker(), *orthancApiClient_)); | 2910 scene_.reset(new RadiologyScene(GetBroker(), *orthancApiClient_)); |
2900 stack_->LoadFrame(instance, frame, false); //.SetPan(200, 0); | 2911 scene_->LoadDicomFrame(instance, frame, false); //.SetPan(200, 0); |
2901 //stack_->LoadFrame("61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", 0, false); | 2912 //scene_->LoadDicomFrame("61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", 0, false); |
2902 | 2913 |
2903 { | 2914 { |
2904 BitmapStack::Bitmap& bitmap = stack_->LoadText(fonts.GetFont(0), "Hello\nworld"); | 2915 RadiologyScene::Layer& layer = scene_->LoadText(fonts.GetFont(0), "Hello\nworld"); |
2905 //dynamic_cast<BitmapStack::AlphaBitmap&>(bitmap).SetForegroundValue(256); | 2916 //dynamic_cast<RadiologyScene::Layer&>(layer).SetForegroundValue(256); |
2906 dynamic_cast<BitmapStack::AlphaBitmap&>(bitmap).SetResizeable(true); | 2917 dynamic_cast<RadiologyScene::Layer&>(layer).SetResizeable(true); |
2907 } | 2918 } |
2908 | 2919 |
2909 { | 2920 { |
2910 BitmapStack::Bitmap& bitmap = stack_->LoadTestBlock(100, 50); | 2921 RadiologyScene::Layer& layer = scene_->LoadTestBlock(100, 50); |
2911 //dynamic_cast<BitmapStack::AlphaBitmap&>(bitmap).SetForegroundValue(256); | 2922 //dynamic_cast<RadiologyScene::Layer&>(layer).SetForegroundValue(256); |
2912 dynamic_cast<BitmapStack::AlphaBitmap&>(bitmap).SetResizeable(true); | 2923 dynamic_cast<RadiologyScene::Layer&>(layer).SetResizeable(true); |
2913 dynamic_cast<BitmapStack::AlphaBitmap&>(bitmap).SetPan(0, 200); | 2924 dynamic_cast<RadiologyScene::Layer&>(layer).SetPan(0, 200); |
2914 } | 2925 } |
2915 | 2926 |
2916 | 2927 |
2917 mainWidget_ = new BitmapStackWidget(GetBroker(), *stack_, "main-widget"); | 2928 mainWidget_ = new RadiologyWidget(GetBroker(), *scene_, "main-widget"); |
2918 mainWidget_->SetTransmitMouseOver(true); | 2929 mainWidget_->SetTransmitMouseOver(true); |
2919 mainWidget_->SetInteractor(interactor_); | 2930 mainWidget_->SetInteractor(interactor_); |
2920 | 2931 |
2921 //stack_->SetWindowing(128, 256); | 2932 //scene_->SetWindowing(128, 256); |
2922 } | 2933 } |
2923 }; | 2934 }; |
2924 } | 2935 } |
2925 } | 2936 } |