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 :