Mercurial > hg > orthanc-stone
comparison Applications/Samples/SingleFrameEditorApplication.h @ 413:18b707fb8620
reorganization
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 12 Nov 2018 17:17:25 +0100 |
parents | 6decc0ba9da5 |
children | f7616c010056 |
comparison
equal
deleted
inserted
replaced
412:71c16998fcc8 | 413:18b707fb8620 |
---|---|
22 #pragma once | 22 #pragma once |
23 | 23 |
24 #include "SampleApplicationBase.h" | 24 #include "SampleApplicationBase.h" |
25 | 25 |
26 #include "../../Framework/Radiography/RadiographyScene.h" | 26 #include "../../Framework/Radiography/RadiographyScene.h" |
27 #include "../../Framework/Radiography/RadiographyWidget.h" | |
27 | 28 |
28 #include "../../Framework/Toolbox/UndoRedoStack.h" | 29 #include "../../Framework/Toolbox/UndoRedoStack.h" |
29 | 30 |
30 #include <Core/Images/FontRegistry.h> | 31 #include <Core/Images/FontRegistry.h> |
31 #include <Core/Images/Image.h> | 32 #include <Core/Images/Image.h> |
49 #include <boost/math/special_functions/round.hpp> | 50 #include <boost/math/special_functions/round.hpp> |
50 | 51 |
51 | 52 |
52 namespace OrthancStone | 53 namespace OrthancStone |
53 { | 54 { |
54 class RadiographyLayerCommand : public UndoRedoStack::ICommand | 55 class RadiographySceneCommand : public UndoRedoStack::ICommand |
55 { | 56 { |
56 private: | 57 private: |
57 RadiographyScene& scene_; | 58 RadiographyScene& scene_; |
58 size_t layer_; | 59 size_t layer_; |
59 | 60 |
61 virtual void UndoInternal(RadiographyLayer& layer) const = 0; | 62 virtual void UndoInternal(RadiographyLayer& layer) const = 0; |
62 | 63 |
63 virtual void RedoInternal(RadiographyLayer& layer) const = 0; | 64 virtual void RedoInternal(RadiographyLayer& layer) const = 0; |
64 | 65 |
65 public: | 66 public: |
66 RadiographyLayerCommand(RadiographyScene& scene, | 67 RadiographySceneCommand(RadiographyScene& scene, |
67 size_t layer) : | 68 size_t layer) : |
68 scene_(scene), | 69 scene_(scene), |
69 layer_(layer) | 70 layer_(layer) |
70 { | 71 { |
71 } | 72 } |
72 | 73 |
73 RadiographyLayerCommand(const RadiographyScene::LayerAccessor& accessor) : | 74 RadiographySceneCommand(const RadiographyScene::LayerAccessor& accessor) : |
74 scene_(accessor.GetScene()), | 75 scene_(accessor.GetScene()), |
75 layer_(accessor.GetIndex()) | 76 layer_(accessor.GetIndex()) |
76 { | 77 { |
77 } | 78 } |
78 | 79 |
129 return false; | 130 return false; |
130 } | 131 } |
131 } | 132 } |
132 | 133 |
133 | 134 |
134 class UndoRedoCommand : public RadiographyLayerCommand | 135 class UndoRedoCommand : public RadiographySceneCommand |
135 { | 136 { |
136 private: | 137 private: |
137 double sourceAngle_; | 138 double sourceAngle_; |
138 double targetAngle_; | 139 double targetAngle_; |
139 | 140 |
155 layer.SetAngle(targetAngle_); | 156 layer.SetAngle(targetAngle_); |
156 } | 157 } |
157 | 158 |
158 public: | 159 public: |
159 UndoRedoCommand(const RadiographyLayerRotateTracker& tracker) : | 160 UndoRedoCommand(const RadiographyLayerRotateTracker& tracker) : |
160 RadiographyLayerCommand(tracker.accessor_), | 161 RadiographySceneCommand(tracker.accessor_), |
161 sourceAngle_(tracker.originalAngle_), | 162 sourceAngle_(tracker.originalAngle_), |
162 targetAngle_(tracker.accessor_.GetLayer().GetAngle()) | 163 targetAngle_(tracker.accessor_.GetLayer().GetAngle()) |
163 { | 164 { |
164 } | 165 } |
165 }; | 166 }; |
245 double clickY_; | 246 double clickY_; |
246 double panX_; | 247 double panX_; |
247 double panY_; | 248 double panY_; |
248 bool oneAxis_; | 249 bool oneAxis_; |
249 | 250 |
250 class UndoRedoCommand : public RadiographyLayerCommand | 251 class UndoRedoCommand : public RadiographySceneCommand |
251 { | 252 { |
252 private: | 253 private: |
253 double sourceX_; | 254 double sourceX_; |
254 double sourceY_; | 255 double sourceY_; |
255 double targetX_; | 256 double targetX_; |
266 layer.SetPan(targetX_, targetY_); | 267 layer.SetPan(targetX_, targetY_); |
267 } | 268 } |
268 | 269 |
269 public: | 270 public: |
270 UndoRedoCommand(const RadiographyLayerMoveTracker& tracker) : | 271 UndoRedoCommand(const RadiographyLayerMoveTracker& tracker) : |
271 RadiographyLayerCommand(tracker.accessor_), | 272 RadiographySceneCommand(tracker.accessor_), |
272 sourceX_(tracker.panX_), | 273 sourceX_(tracker.panX_), |
273 sourceY_(tracker.panY_), | 274 sourceY_(tracker.panY_), |
274 targetX_(tracker.accessor_.GetLayer().GetPanX()), | 275 targetX_(tracker.accessor_.GetLayer().GetPanX()), |
275 targetY_(tracker.accessor_.GetLayer().GetPanY()) | 276 targetY_(tracker.accessor_.GetLayer().GetPanY()) |
276 { | 277 { |
356 unsigned int cropX_; | 357 unsigned int cropX_; |
357 unsigned int cropY_; | 358 unsigned int cropY_; |
358 unsigned int cropWidth_; | 359 unsigned int cropWidth_; |
359 unsigned int cropHeight_; | 360 unsigned int cropHeight_; |
360 | 361 |
361 class UndoRedoCommand : public RadiographyLayerCommand | 362 class UndoRedoCommand : public RadiographySceneCommand |
362 { | 363 { |
363 private: | 364 private: |
364 unsigned int sourceCropX_; | 365 unsigned int sourceCropX_; |
365 unsigned int sourceCropY_; | 366 unsigned int sourceCropY_; |
366 unsigned int sourceCropWidth_; | 367 unsigned int sourceCropWidth_; |
381 layer.SetCrop(targetCropX_, targetCropY_, targetCropWidth_, targetCropHeight_); | 382 layer.SetCrop(targetCropX_, targetCropY_, targetCropWidth_, targetCropHeight_); |
382 } | 383 } |
383 | 384 |
384 public: | 385 public: |
385 UndoRedoCommand(const RadiographyLayerCropTracker& tracker) : | 386 UndoRedoCommand(const RadiographyLayerCropTracker& tracker) : |
386 RadiographyLayerCommand(tracker.accessor_), | 387 RadiographySceneCommand(tracker.accessor_), |
387 sourceCropX_(tracker.cropX_), | 388 sourceCropX_(tracker.cropX_), |
388 sourceCropY_(tracker.cropY_), | 389 sourceCropY_(tracker.cropY_), |
389 sourceCropWidth_(tracker.cropWidth_), | 390 sourceCropWidth_(tracker.cropWidth_), |
390 sourceCropHeight_(tracker.cropHeight_) | 391 sourceCropHeight_(tracker.cropHeight_) |
391 { | 392 { |
502 double dx = x1 - x2; | 503 double dx = x1 - x2; |
503 double dy = y1 - y2; | 504 double dy = y1 - y2; |
504 return sqrt(dx * dx + dy * dy); | 505 return sqrt(dx * dx + dy * dy); |
505 } | 506 } |
506 | 507 |
507 class UndoRedoCommand : public RadiographyLayerCommand | 508 class UndoRedoCommand : public RadiographySceneCommand |
508 { | 509 { |
509 private: | 510 private: |
510 double sourceSpacingX_; | 511 double sourceSpacingX_; |
511 double sourceSpacingY_; | 512 double sourceSpacingY_; |
512 double sourcePanX_; | 513 double sourcePanX_; |
529 layer.SetPan(targetPanX_, targetPanY_); | 530 layer.SetPan(targetPanX_, targetPanY_); |
530 } | 531 } |
531 | 532 |
532 public: | 533 public: |
533 UndoRedoCommand(const RadiographyLayerResizeTracker& tracker) : | 534 UndoRedoCommand(const RadiographyLayerResizeTracker& tracker) : |
534 RadiographyLayerCommand(tracker.accessor_), | 535 RadiographySceneCommand(tracker.accessor_), |
535 sourceSpacingX_(tracker.originalSpacingX_), | 536 sourceSpacingX_(tracker.originalSpacingX_), |
536 sourceSpacingY_(tracker.originalSpacingY_), | 537 sourceSpacingY_(tracker.originalSpacingY_), |
537 sourcePanX_(tracker.originalPanX_), | 538 sourcePanX_(tracker.originalPanX_), |
538 sourcePanY_(tracker.originalPanY_), | 539 sourcePanY_(tracker.originalPanY_), |
539 targetSpacingX_(tracker.accessor_.GetLayer().GetPixelSpacingX()), | 540 targetSpacingX_(tracker.accessor_.GetLayer().GetPixelSpacingX()), |
847 scene_.SetWindowing(newCenter, newWidth); | 848 scene_.SetWindowing(newCenter, newWidth); |
848 } | 849 } |
849 }; | 850 }; |
850 | 851 |
851 | 852 |
852 class RadiographyWidget : | |
853 public WorldSceneWidget, | |
854 public IObserver | |
855 { | |
856 private: | |
857 RadiographyScene& scene_; | |
858 std::auto_ptr<Orthanc::Image> floatBuffer_; | |
859 std::auto_ptr<CairoSurface> cairoBuffer_; | |
860 bool invert_; | |
861 ImageInterpolation interpolation_; | |
862 bool hasSelection_; | |
863 size_t selectedLayer_; | |
864 | |
865 virtual bool RenderInternal(unsigned int width, | |
866 unsigned int height, | |
867 ImageInterpolation interpolation) | |
868 { | |
869 float windowCenter, windowWidth; | |
870 scene_.GetWindowingWithDefault(windowCenter, windowWidth); | |
871 | |
872 float x0 = windowCenter - windowWidth / 2.0f; | |
873 float x1 = windowCenter + windowWidth / 2.0f; | |
874 | |
875 if (windowWidth <= 0.001f) // Avoid division by zero at (*) | |
876 { | |
877 return false; | |
878 } | |
879 else | |
880 { | |
881 if (floatBuffer_.get() == NULL || | |
882 floatBuffer_->GetWidth() != width || | |
883 floatBuffer_->GetHeight() != height) | |
884 { | |
885 floatBuffer_.reset(new Orthanc::Image(Orthanc::PixelFormat_Float32, width, height, false)); | |
886 } | |
887 | |
888 if (cairoBuffer_.get() == NULL || | |
889 cairoBuffer_->GetWidth() != width || | |
890 cairoBuffer_->GetHeight() != height) | |
891 { | |
892 cairoBuffer_.reset(new CairoSurface(width, height)); | |
893 } | |
894 | |
895 scene_.Render(*floatBuffer_, GetView().GetMatrix(), interpolation); | |
896 | |
897 // Conversion from Float32 to BGRA32 (cairo). Very similar to | |
898 // GrayscaleFrameRenderer => TODO MERGE? | |
899 | |
900 Orthanc::ImageAccessor target; | |
901 cairoBuffer_->GetWriteableAccessor(target); | |
902 | |
903 float scaling = 255.0f / (x1 - x0); | |
904 | |
905 for (unsigned int y = 0; y < height; y++) | |
906 { | |
907 const float* p = reinterpret_cast<const float*>(floatBuffer_->GetConstRow(y)); | |
908 uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y)); | |
909 | |
910 for (unsigned int x = 0; x < width; x++, p++, q += 4) | |
911 { | |
912 uint8_t v = 0; | |
913 if (*p >= x1) | |
914 { | |
915 v = 255; | |
916 } | |
917 else if (*p <= x0) | |
918 { | |
919 v = 0; | |
920 } | |
921 else | |
922 { | |
923 // https://en.wikipedia.org/wiki/Linear_interpolation | |
924 v = static_cast<uint8_t>(scaling * (*p - x0)); // (*) | |
925 } | |
926 | |
927 if (invert_) | |
928 { | |
929 v = 255 - v; | |
930 } | |
931 | |
932 q[0] = v; | |
933 q[1] = v; | |
934 q[2] = v; | |
935 q[3] = 255; | |
936 } | |
937 } | |
938 | |
939 return true; | |
940 } | |
941 } | |
942 | |
943 protected: | |
944 virtual Extent2D GetSceneExtent() | |
945 { | |
946 return scene_.GetSceneExtent(); | |
947 } | |
948 | |
949 virtual bool RenderScene(CairoContext& context, | |
950 const ViewportGeometry& view) | |
951 { | |
952 cairo_t* cr = context.GetObject(); | |
953 | |
954 if (RenderInternal(context.GetWidth(), context.GetHeight(), interpolation_)) | |
955 { | |
956 // https://www.cairographics.org/FAQ/#paint_from_a_surface | |
957 cairo_save(cr); | |
958 cairo_identity_matrix(cr); | |
959 cairo_set_source_surface(cr, cairoBuffer_->GetObject(), 0, 0); | |
960 cairo_paint(cr); | |
961 cairo_restore(cr); | |
962 } | |
963 else | |
964 { | |
965 // https://www.cairographics.org/FAQ/#clear_a_surface | |
966 context.SetSourceColor(0, 0, 0); | |
967 cairo_paint(cr); | |
968 } | |
969 | |
970 if (hasSelection_) | |
971 { | |
972 scene_.DrawBorder(context, selectedLayer_, view.GetZoom()); | |
973 } | |
974 | |
975 return true; | |
976 } | |
977 | |
978 public: | |
979 RadiographyWidget(MessageBroker& broker, | |
980 RadiographyScene& scene, | |
981 const std::string& name) : | |
982 WorldSceneWidget(name), | |
983 IObserver(broker), | |
984 scene_(scene), | |
985 invert_(false), | |
986 interpolation_(ImageInterpolation_Nearest), | |
987 hasSelection_(false), | |
988 selectedLayer_(0) // Dummy initialization | |
989 { | |
990 scene.RegisterObserverCallback( | |
991 new Callable<RadiographyWidget, RadiographyScene::GeometryChangedMessage> | |
992 (*this, &RadiographyWidget::OnGeometryChanged)); | |
993 | |
994 scene.RegisterObserverCallback( | |
995 new Callable<RadiographyWidget, RadiographyScene::ContentChangedMessage> | |
996 (*this, &RadiographyWidget::OnContentChanged)); | |
997 } | |
998 | |
999 RadiographyScene& GetScene() const | |
1000 { | |
1001 return scene_; | |
1002 } | |
1003 | |
1004 void Unselect() | |
1005 { | |
1006 hasSelection_ = false; | |
1007 } | |
1008 | |
1009 void Select(size_t layer) | |
1010 { | |
1011 hasSelection_ = true; | |
1012 selectedLayer_ = layer; | |
1013 } | |
1014 | |
1015 bool LookupSelectedLayer(size_t& layer) | |
1016 { | |
1017 if (hasSelection_) | |
1018 { | |
1019 layer = selectedLayer_; | |
1020 return true; | |
1021 } | |
1022 else | |
1023 { | |
1024 return false; | |
1025 } | |
1026 } | |
1027 | |
1028 void OnGeometryChanged(const RadiographyScene::GeometryChangedMessage& message) | |
1029 { | |
1030 LOG(INFO) << "Geometry has changed"; | |
1031 FitContent(); | |
1032 } | |
1033 | |
1034 void OnContentChanged(const RadiographyScene::ContentChangedMessage& message) | |
1035 { | |
1036 LOG(INFO) << "Content has changed"; | |
1037 NotifyContentChanged(); | |
1038 } | |
1039 | |
1040 void SetInvert(bool invert) | |
1041 { | |
1042 if (invert_ != invert) | |
1043 { | |
1044 invert_ = invert; | |
1045 NotifyContentChanged(); | |
1046 } | |
1047 } | |
1048 | |
1049 void SwitchInvert() | |
1050 { | |
1051 invert_ = !invert_; | |
1052 NotifyContentChanged(); | |
1053 } | |
1054 | |
1055 bool IsInverted() const | |
1056 { | |
1057 return invert_; | |
1058 } | |
1059 | |
1060 void SetInterpolation(ImageInterpolation interpolation) | |
1061 { | |
1062 if (interpolation_ != interpolation) | |
1063 { | |
1064 interpolation_ = interpolation; | |
1065 NotifyContentChanged(); | |
1066 } | |
1067 } | |
1068 | |
1069 ImageInterpolation GetInterpolation() const | |
1070 { | |
1071 return interpolation_; | |
1072 } | |
1073 }; | |
1074 | 853 |
1075 | 854 |
1076 namespace Samples | 855 namespace Samples |
1077 { | 856 { |
1078 class RadiographyEditorInteractor : | 857 class RadiographyEditorInteractor : |