comparison Applications/Samples/Deprecated/SingleFrameApplication.h @ 1347:bfd77672d825 broker

Moved Application/Samples/* to Application/Samples/Deprecated/*
author Benjamin Golinvaux <bgo@osimis.io>
date Tue, 07 Apr 2020 14:29:01 +0200
parents Applications/Samples/SingleFrameApplication.h@257f2c9a02ac
children c53a4667f895
comparison
equal deleted inserted replaced
1346:df8bf351c23f 1347:bfd77672d825
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21
22 #pragma once
23
24 #include "SampleApplicationBase.h"
25
26 #include "../../Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h"
27 #include "../../Framework/Deprecated/Widgets/SliceViewerWidget.h"
28
29 #include <Core/Logging.h>
30 #include <Core/OrthancException.h>
31
32 #include <boost/math/constants/constants.hpp>
33
34
35 namespace OrthancStone
36 {
37 namespace Samples
38 {
39 class SingleFrameApplication :
40 public SampleSingleCanvasApplicationBase,
41 public ObserverBase<SingleFrameApplication>
42 {
43 private:
44 class Interactor : public Deprecated::IWorldSceneInteractor
45 {
46 private:
47 SingleFrameApplication& application_;
48
49 public:
50 Interactor(SingleFrameApplication& application) :
51 application_(application)
52 {
53 }
54
55 virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
56 const Deprecated::ViewportGeometry& view,
57 MouseButton button,
58 KeyboardModifiers modifiers,
59 int viewportX,
60 int viewportY,
61 double x,
62 double y,
63 Deprecated::IStatusBar* statusBar,
64 const std::vector<Deprecated::Touch>& displayTouches)
65 {
66 return NULL;
67 }
68
69 virtual void MouseOver(CairoContext& context,
70 Deprecated::WorldSceneWidget& widget,
71 const Deprecated::ViewportGeometry& view,
72 double x,
73 double y,
74 Deprecated::IStatusBar* statusBar)
75 {
76 if (statusBar != NULL)
77 {
78 Vector p = dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
79
80 char buf[64];
81 sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)",
82 p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
83 statusBar->SetMessage(buf);
84 }
85 }
86
87 virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
88 MouseWheelDirection direction,
89 KeyboardModifiers modifiers,
90 Deprecated::IStatusBar* statusBar)
91 {
92 int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1);
93
94 switch (direction)
95 {
96 case MouseWheelDirection_Up:
97 application_.OffsetSlice(-scale);
98 break;
99
100 case MouseWheelDirection_Down:
101 application_.OffsetSlice(scale);
102 break;
103
104 default:
105 break;
106 }
107 }
108
109 virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
110 KeyboardKeys key,
111 char keyChar,
112 KeyboardModifiers modifiers,
113 Deprecated::IStatusBar* statusBar)
114 {
115 switch (keyChar)
116 {
117 case 's':
118 widget.FitContent();
119 break;
120
121 default:
122 break;
123 }
124 }
125 };
126
127
128 void OffsetSlice(int offset)
129 {
130 if (source_)
131 {
132 int slice = static_cast<int>(slice_) + offset;
133
134 if (slice < 0)
135 {
136 slice = 0;
137 }
138
139 if (slice >= static_cast<int>(source_->GetSlicesCount()))
140 {
141 slice = static_cast<int>(source_->GetSlicesCount()) - 1;
142 }
143
144 if (slice != static_cast<int>(slice_))
145 {
146 SetSlice(slice);
147 }
148 }
149 }
150
151
152 void SetSlice(size_t index)
153 {
154 if (source_ &&
155 index < source_->GetSlicesCount())
156 {
157 slice_ = static_cast<unsigned int>(index);
158
159 #if 1
160 widget_->SetSlice(source_->GetSlice(slice_).GetGeometry());
161 #else
162 // TEST for scene extents - Rotate the axes
163 double a = 15.0 / 180.0 * boost::math::constants::pi<double>();
164
165 #if 1
166 Vector x; GeometryToolbox::AssignVector(x, cos(a), sin(a), 0);
167 Vector y; GeometryToolbox::AssignVector(y, -sin(a), cos(a), 0);
168 #else
169 // Flip the normal
170 Vector x; GeometryToolbox::AssignVector(x, cos(a), sin(a), 0);
171 Vector y; GeometryToolbox::AssignVector(y, sin(a), -cos(a), 0);
172 #endif
173
174 SliceGeometry s(source_->GetSlice(slice_).GetGeometry().GetOrigin(), x, y);
175 widget_->SetSlice(s);
176 #endif
177 }
178 }
179
180
181 void OnMainWidgetGeometryReady(const Deprecated::IVolumeSlicer::GeometryReadyMessage& message)
182 {
183 // Once the geometry of the series is downloaded from Orthanc,
184 // display its middle slice, and adapt the viewport to fit this
185 // slice
186 if (source_ &&
187 source_.get() == &message.GetOrigin())
188 {
189 SetSlice(source_->GetSlicesCount() / 2);
190 }
191
192 widget_->FitContent();
193 }
194
195 boost::shared_ptr<Deprecated::SliceViewerWidget> widget_;
196 std::unique_ptr<Interactor> mainWidgetInteractor_;
197 boost::shared_ptr<Deprecated::DicomSeriesVolumeSlicer> source_;
198 unsigned int slice_;
199
200 public:
201 SingleFrameApplication() :
202 slice_(0)
203 {
204 }
205
206 virtual void DeclareStartupOptions(boost::program_options::options_description& options)
207 {
208 boost::program_options::options_description generic("Sample options");
209 generic.add_options()
210 ("instance", boost::program_options::value<std::string>(),
211 "Orthanc ID of the instance")
212 ("frame", boost::program_options::value<unsigned int>()->default_value(0),
213 "Number of the frame, for multi-frame DICOM instances")
214 ("smooth", boost::program_options::value<bool>()->default_value(true),
215 "Enable bilinear interpolation to smooth the image")
216 ;
217
218 options.add(generic);
219 }
220
221 virtual void Initialize(StoneApplicationContext* context,
222 Deprecated::IStatusBar& statusBar,
223 const boost::program_options::variables_map& parameters)
224 {
225 using namespace OrthancStone;
226
227 context_ = context;
228
229 statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
230
231 if (parameters.count("instance") != 1)
232 {
233 LOG(ERROR) << "The instance ID is missing";
234 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
235 }
236
237 std::string instance = parameters["instance"].as<std::string>();
238 int frame = parameters["frame"].as<unsigned int>();
239
240 widget_.reset(new Deprecated::SliceViewerWidget("main-widget"));
241 SetCentralWidget(widget_);
242
243 boost::shared_ptr<Deprecated::DicomSeriesVolumeSlicer> layer(new Deprecated::DicomSeriesVolumeSlicer);
244 layer->Connect(context->GetOrthancApiClient());
245 source_ = layer;
246
247 layer->LoadFrame(instance, frame);
248 Register<Deprecated::IVolumeSlicer::GeometryReadyMessage>(*layer, &SingleFrameApplication::OnMainWidgetGeometryReady);
249 widget_->AddLayer(layer);
250
251 Deprecated::RenderStyle s;
252
253 if (parameters["smooth"].as<bool>())
254 {
255 s.interpolation_ = ImageInterpolation_Bilinear;
256 }
257
258 widget_->SetLayerStyle(0, s);
259 widget_->SetTransmitMouseOver(true);
260
261 mainWidgetInteractor_.reset(new Interactor(*this));
262 widget_->SetInteractor(*mainWidgetInteractor_);
263 }
264 };
265
266
267 }
268 }