comparison Applications/Samples/SingleFrameEditorApplication.h @ 347:cd65103c9172 am-2

RotateBitmapTracker
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 23 Oct 2018 10:50:46 +0200
parents c2e040ea8fbe
children dadee0f7f1b3
comparison
equal deleted inserted replaced
346:c2e040ea8fbe 347:cd65103c9172
47 { 47 {
48 public: 48 public:
49 typedef OriginMessage<MessageType_Widget_GeometryChanged, BitmapStack> GeometryChangedMessage; 49 typedef OriginMessage<MessageType_Widget_GeometryChanged, BitmapStack> GeometryChangedMessage;
50 typedef OriginMessage<MessageType_Widget_ContentChanged, BitmapStack> ContentChangedMessage; 50 typedef OriginMessage<MessageType_Widget_ContentChanged, BitmapStack> ContentChangedMessage;
51 51
52 private:
53 class Bitmap : public boost::noncopyable 52 class Bitmap : public boost::noncopyable
54 { 53 {
55 private: 54 private:
56 bool visible_; 55 bool visible_;
57 bool hasSize_; 56 bool hasSize_;
124 123
125 void UpdateTransform() 124 void UpdateTransform()
126 { 125 {
127 transform_ = CreateScalingMatrix(pixelSpacingX_, pixelSpacingY_); 126 transform_ = CreateScalingMatrix(pixelSpacingX_, pixelSpacingY_);
128 127
129 double centerX = static_cast<double>(width_) / 2.0; 128 double centerX, centerY;
130 double centerY = static_cast<double>(height_) / 2.0; 129 GetCenter(centerX, centerY);
131 ApplyTransform(centerX, centerY, transform_);
132 130
133 transform_ = LinearAlgebra::Product( 131 transform_ = LinearAlgebra::Product(
134 CreateOffsetMatrix(panX_ + centerX, panY_ + centerY), 132 CreateOffsetMatrix(panX_ + centerX, panY_ + centerY),
135 CreateRotationMatrix(angle_), 133 CreateRotationMatrix(angle_),
136 CreateOffsetMatrix(-centerX, -centerY), transform_); 134 CreateOffsetMatrix(-centerX, -centerY),
135 transform_);
137 } 136 }
138 137
139 138
140 void AddToExtent(Extent2D& extent, 139 void AddToExtent(Extent2D& extent,
141 double x, 140 double x,
155 hasCrop_(false), 154 hasCrop_(false),
156 pixelSpacingX_(1), 155 pixelSpacingX_(1),
157 pixelSpacingY_(1), 156 pixelSpacingY_(1),
158 panX_(0), 157 panX_(0),
159 panY_(0), 158 panY_(0),
160 angle_(45.0 / 180.0 * boost::math::constants::pi<double>()) 159 angle_(0)
161 { 160 {
162 UpdateTransform(); 161 UpdateTransform();
163 } 162 }
164 163
165 virtual ~Bitmap() 164 virtual ~Bitmap()
355 { 354 {
356 return transform_; 355 return transform_;
357 } 356 }
358 357
359 358
359 void GetCenter(double& centerX,
360 double& centerY) const
361 {
362 centerX = static_cast<double>(width_) / 2.0;
363 centerY = static_cast<double>(height_) / 2.0;
364 ApplyTransform(centerX, centerY, transform_);
365 }
366
367
360 void DrawBorders(CairoContext& context, 368 void DrawBorders(CairoContext& context,
361 double zoom) 369 double zoom)
362 { 370 {
363 unsigned int cx, cy, width, height; 371 unsigned int cx, cy, width, height;
364 GetCrop(cx, cy, width, height); 372 GetCrop(cx, cy, width, height);
400 cairo_stroke(cr); 408 cairo_stroke(cr);
401 } 409 }
402 }; 410 };
403 411
404 412
405 413 class BitmapAccessor : public boost::noncopyable
414 {
415 private:
416 size_t index_;
417 Bitmap* bitmap_;
418
419 public:
420 BitmapAccessor(BitmapStack& stack,
421 size_t index) :
422 index_(index)
423 {
424 Bitmaps::iterator bitmap = stack.bitmaps_.find(index);
425 if (bitmap == stack.bitmaps_.end())
426 {
427 bitmap_ = NULL;
428 }
429 else
430 {
431 assert(bitmap->second != NULL);
432 bitmap_ = bitmap->second;
433 }
434 }
435
436 BitmapAccessor(BitmapStack& stack,
437 double x,
438 double y) :
439 index_(0) // Dummy initialization
440 {
441 if (stack.LookupBitmap(index_, x, y))
442 {
443 Bitmaps::iterator bitmap = stack.bitmaps_.find(index_);
444
445 if (bitmap == stack.bitmaps_.end())
446 {
447 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
448 }
449 else
450 {
451 assert(bitmap->second != NULL);
452 bitmap_ = bitmap->second;
453 }
454 }
455 else
456 {
457 bitmap_ = NULL;
458 }
459 }
460
461 void Invalidate()
462 {
463 bitmap_ = NULL;
464 }
465
466 bool IsValid() const
467 {
468 return bitmap_ != NULL;
469 }
470
471 size_t GetIndex() const
472 {
473 if (IsValid())
474 {
475 return index_;
476 }
477 else
478 {
479 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
480 }
481 }
482
483 Bitmap& GetBitmap() const
484 {
485 if (IsValid())
486 {
487 return *bitmap_;
488 }
489 else
490 {
491 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
492 }
493 }
494 };
495
496
497 private:
406 class DicomBitmap : public Bitmap 498 class DicomBitmap : public Bitmap
407 { 499 {
408 private: 500 private:
409 std::auto_ptr<Orthanc::ImageAccessor> source_; // Content of PixelData 501 std::auto_ptr<Orthanc::ImageAccessor> source_; // Content of PixelData
410 std::auto_ptr<DicomFrameConverter> converter_; 502 std::auto_ptr<DicomFrameConverter> converter_;
744 } 836 }
745 837
746 838
747 void OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) 839 void OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message)
748 { 840 {
749 size_t index = dynamic_cast<Orthanc::SingleValueObject<size_t>*>(message.Payload.get())->GetValue(); 841 size_t index = dynamic_cast<Orthanc::SingleValueObject<size_t>*>(message.Payload.get())->GetValue();
750 842
751 printf("JSON received: [%s] (%ld bytes) for bitmap %ld\n", 843 printf("JSON received: [%s] (%ld bytes) for bitmap %ld\n",
752 message.Uri.c_str(), message.AnswerSize, index); 844 message.Uri.c_str(), message.AnswerSize, index);
753 845
754 Bitmaps::iterator bitmap = bitmaps_.find(index); 846 Bitmaps::iterator bitmap = bitmaps_.find(index);
773 } 865 }
774 866
775 867
776 void OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) 868 void OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message)
777 { 869 {
778 size_t index = dynamic_cast<Orthanc::SingleValueObject<size_t>*>(message.Payload.get())->GetValue(); 870 size_t index = dynamic_cast<Orthanc::SingleValueObject<size_t>*>(message.Payload.get())->GetValue();
779 871
780 printf("Frame received: [%s] (%ld bytes) for bitmap %ld\n", 872 printf("Frame received: [%s] (%ld bytes) for bitmap %ld\n",
781 message.Uri.c_str(), message.AnswerSize, index); 873 message.Uri.c_str(), message.AnswerSize, index);
782 874
783 Bitmaps::iterator bitmap = bitmaps_.find(index); 875 Bitmaps::iterator bitmap = bitmaps_.find(index);
854 } 946 }
855 947
856 return false; 948 return false;
857 } 949 }
858 950
859
860 void SetPan(size_t index,
861 double panX,
862 double panY)
863 {
864 Bitmaps::iterator bitmap = bitmaps_.find(index);
865 if (bitmap != bitmaps_.end())
866 {
867 assert(bitmap->second != NULL);
868 bitmap->second->SetPan(panX, panY);
869 }
870 }
871
872
873 void GetPan(double& panX,
874 double& panY,
875 size_t index) const
876 {
877 Bitmaps::const_iterator bitmap = bitmaps_.find(index);
878 if (bitmap != bitmaps_.end())
879 {
880 assert(bitmap->second != NULL);
881 panX = bitmap->second->GetPanX();
882 panY = bitmap->second->GetPanY();
883 }
884 else
885 {
886 panX = 0;
887 panY = 0;
888 }
889 }
890
891
892 void DrawControls(CairoSurface& surface, 951 void DrawControls(CairoSurface& surface,
893 const ViewportGeometry& view) 952 const ViewportGeometry& view)
894 { 953 {
895 if (hasSelection_) 954 if (hasSelection_)
896 { 955 {
910 969
911 970
912 class BitmapStackInteractor : public IWorldSceneInteractor 971 class BitmapStackInteractor : public IWorldSceneInteractor
913 { 972 {
914 private: 973 private:
974 enum Tool
975 {
976 Tool_Move,
977 Tool_Rotate
978 };
979
980
915 BitmapStack& stack_; 981 BitmapStack& stack_;
916 982 Tool tool_;
917 983
984
985 class RotateBitmapTracker : public IWorldSceneMouseTracker
986 {
987 private:
988 BitmapStack::BitmapAccessor accessor_;
989 double centerX_;
990 double centerY_;
991 double originalAngle_;
992 double clickAngle_;
993 bool roundAngles_;
994
995 bool ComputeAngle(double& angle /* out */,
996 double sceneX,
997 double sceneY)
998 {
999 Vector u;
1000 LinearAlgebra::AssignVector(u, sceneX - centerX_, sceneY - centerY_);
1001
1002 double nu = boost::numeric::ublas::norm_2(u);
1003
1004 if (!LinearAlgebra::IsCloseToZero(nu))
1005 {
1006 u /= nu;
1007 angle = atan2(u[1], u[0]);
1008 return true;
1009 }
1010 else
1011 {
1012 return false;
1013 }
1014 }
1015
1016
1017 public:
1018 RotateBitmapTracker(BitmapStack& stack,
1019 const ViewportGeometry& view,
1020 size_t bitmap,
1021 double x,
1022 double y,
1023 bool roundAngles) :
1024 accessor_(stack, bitmap),
1025 roundAngles_(roundAngles)
1026 {
1027 if (accessor_.IsValid())
1028 {
1029 accessor_.GetBitmap().GetCenter(centerX_, centerY_);
1030 originalAngle_ = accessor_.GetBitmap().GetAngle();
1031
1032 double sceneX, sceneY;
1033 view.MapDisplayToScene(sceneX, sceneY, x, y);
1034
1035 if (!ComputeAngle(clickAngle_, x, y))
1036 {
1037 accessor_.Invalidate();
1038 }
1039 }
1040 }
1041
1042 virtual bool HasRender() const
1043 {
1044 return false;
1045 }
1046
1047 virtual void Render(CairoContext& context,
1048 double zoom)
1049 {
1050 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
1051 }
1052
1053 virtual void MouseUp()
1054 {
1055 }
1056
1057 virtual void MouseMove(int displayX,
1058 int displayY,
1059 double sceneX,
1060 double sceneY)
1061 {
1062 static const double ROUND_ANGLE = 15.0 / 180.0 * boost::math::constants::pi<double>();
1063
1064 double angle;
1065
1066 if (accessor_.IsValid() &&
1067 ComputeAngle(angle, sceneX, sceneY))
1068 {
1069 angle = angle - clickAngle_ + originalAngle_;
1070
1071 if (roundAngles_)
1072 {
1073 angle = round(angle / ROUND_ANGLE) * ROUND_ANGLE;
1074 }
1075
1076 accessor_.GetBitmap().SetAngle(angle);
1077 }
1078 }
1079 };
1080
1081
918 class MoveBitmapTracker : public IWorldSceneMouseTracker 1082 class MoveBitmapTracker : public IWorldSceneMouseTracker
919 { 1083 {
920 private: 1084 private:
921 BitmapStack& stack_; 1085 BitmapStack::BitmapAccessor accessor_;
922 size_t bitmap_; 1086 double clickX_;
923 double clickX_; 1087 double clickY_;
924 double clickY_; 1088 double panX_;
925 double panX_; 1089 double panY_;
926 double panY_; 1090 bool oneAxis_;
927 bool oneAxis_;
928 1091
929 public: 1092 public:
930 MoveBitmapTracker(BitmapStack& stack, 1093 MoveBitmapTracker(BitmapStack& stack,
931 size_t bitmap, 1094 size_t bitmap,
932 double x, 1095 double x,
933 double y, 1096 double y,
934 bool oneAxis) : 1097 bool oneAxis) :
935 stack_(stack), 1098 accessor_(stack, bitmap),
936 bitmap_(bitmap),
937 clickX_(x), 1099 clickX_(x),
938 clickY_(y), 1100 clickY_(y),
939 oneAxis_(oneAxis) 1101 oneAxis_(oneAxis)
940 { 1102 {
941 stack.GetPan(panX_, panY_, bitmap_); 1103 if (accessor_.IsValid())
1104 {
1105 panX_ = accessor_.GetBitmap().GetPanX();
1106 panY_ = accessor_.GetBitmap().GetPanY();
1107 }
942 } 1108 }
943 1109
944 virtual bool HasRender() const 1110 virtual bool HasRender() const
945 { 1111 {
946 return false; 1112 return false;
959 virtual void MouseMove(int displayX, 1125 virtual void MouseMove(int displayX,
960 int displayY, 1126 int displayY,
961 double sceneX, 1127 double sceneX,
962 double sceneY) 1128 double sceneY)
963 { 1129 {
964 double dx = sceneX - clickX_; 1130 if (accessor_.IsValid())
965 double dy = sceneY - clickY_; 1131 {
966 1132 double dx = sceneX - clickX_;
967 if (oneAxis_) 1133 double dy = sceneY - clickY_;
968 { 1134
969 if (fabs(dx) > fabs(dy)) 1135 if (oneAxis_)
970 { 1136 {
971 stack_.SetPan(bitmap_, dx + panX_, panY_); 1137 if (fabs(dx) > fabs(dy))
1138 {
1139 accessor_.GetBitmap().SetPan(dx + panX_, panY_);
1140 }
1141 else
1142 {
1143 accessor_.GetBitmap().SetPan(panX_, dy + panY_);
1144 }
972 } 1145 }
973 else 1146 else
974 { 1147 {
975 stack_.SetPan(bitmap_, panX_, dy + panY_); 1148 accessor_.GetBitmap().SetPan(dx + panX_, dy + panY_);
976 } 1149 }
977 }
978 else
979 {
980 stack_.SetPan(bitmap_, dx + panX_, dy + panY_);
981 } 1150 }
982 } 1151 }
983 }; 1152 };
984 1153
985 1154
986 public: 1155 public:
987 BitmapStackInteractor(BitmapStack& stack) : 1156 BitmapStackInteractor(BitmapStack& stack) :
988 stack_(stack) 1157 stack_(stack),
1158 tool_(Tool_Move)
989 { 1159 {
990 } 1160 }
991 1161
992 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, 1162 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
993 const ViewportGeometry& view, 1163 const ViewportGeometry& view,
1007 1177
1008 size_t selected; 1178 size_t selected;
1009 if (stack_.GetSelectedBitmap(selected) && 1179 if (stack_.GetSelectedBitmap(selected) &&
1010 bitmap == selected) 1180 bitmap == selected)
1011 { 1181 {
1012 return new MoveBitmapTracker(stack_, bitmap, x, y, 1182 switch (tool_)
1013 (modifiers & KeyboardModifiers_Shift)); 1183 {
1184 case Tool_Move:
1185 return new MoveBitmapTracker(stack_, bitmap, x, y,
1186 (modifiers & KeyboardModifiers_Shift));
1187
1188 case Tool_Rotate:
1189 return new RotateBitmapTracker(stack_, view, bitmap, x, y,
1190 (modifiers & KeyboardModifiers_Shift));
1191
1192 default:
1193 return NULL;
1194 }
1014 } 1195 }
1015 else 1196 else
1016 { 1197 {
1017 stack_.Select(bitmap); 1198 stack_.Select(bitmap);
1018 return NULL; 1199 return NULL;
1051 KeyboardKeys key, 1232 KeyboardKeys key,
1052 char keyChar, 1233 char keyChar,
1053 KeyboardModifiers modifiers, 1234 KeyboardModifiers modifiers,
1054 IStatusBar* statusBar) 1235 IStatusBar* statusBar)
1055 { 1236 {
1056 if (keyChar == 's') 1237 switch (keyChar)
1057 widget.FitContent(); 1238 {
1239 case 's':
1240 widget.FitContent();
1241 break;
1242
1243 case 'm':
1244 tool_ = Tool_Move;
1245 break;
1246
1247 case 'r':
1248 tool_ = Tool_Rotate;
1249 break;
1250
1251 default:
1252 break;
1253 }
1058 } 1254 }
1059 }; 1255 };
1060 1256
1061 1257
1062 1258