Mercurial > hg > orthanc-stone
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 } |