Mercurial > hg > orthanc-stone
comparison OrthancStone/Samples/Common/RtViewerView.cpp @ 1512:244ad1e4e76a
reorganization of folders
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 07 Jul 2020 16:21:02 +0200 |
parents | Samples/Common/RtViewerView.cpp@169adf9090a6 |
children | 301571299212 |
comparison
equal
deleted
inserted
replaced
1511:9dfeee74c1e6 | 1512:244ad1e4e76a |
---|---|
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 // Sample app | |
23 #include "RtViewerView.h" | |
24 #include "RtViewerApp.h" | |
25 #include "SampleHelpers.h" | |
26 | |
27 #include <EmbeddedResources.h> | |
28 | |
29 // Stone of Orthanc | |
30 #include "../../Sources/Oracle/GetOrthancWebViewerJpegCommand.h" | |
31 #include "../../Sources/Scene2D/CairoCompositor.h" | |
32 #include "../../Sources/Scene2D/ColorTextureSceneLayer.h" | |
33 #include "../../Sources/Scene2D/GrayscaleStyleConfigurator.h" | |
34 #include "../../Sources/Scene2D/LookupTableStyleConfigurator.h" | |
35 #include "../../Sources/Scene2D/OpenGLCompositor.h" | |
36 #include "../../Sources/Scene2D/PanSceneTracker.h" | |
37 #include "../../Sources/Scene2D/RotateSceneTracker.h" | |
38 #include "../../Sources/Scene2D/ZoomSceneTracker.h" | |
39 #include "../../Sources/Scene2DViewport/CreateAngleMeasureTracker.h" | |
40 #include "../../Sources/Scene2DViewport/CreateLineMeasureTracker.h" | |
41 #include "../../Sources/Scene2DViewport/IFlexiblePointerTracker.h" | |
42 #include "../../Sources/Scene2DViewport/MeasureTool.h" | |
43 #include "../../Sources/Scene2DViewport/PredeclaredTypes.h" | |
44 #include "../../Sources/Scene2DViewport/UndoStack.h" | |
45 #include "../../Sources/StoneException.h" | |
46 #include "../../Sources/StoneInitialization.h" | |
47 #include "../../Sources/Volumes/DicomVolumeImageMPRSlicer.h" | |
48 #include "../../Sources/Volumes/VolumeSceneLayerSource.h" | |
49 | |
50 // Orthanc | |
51 #include <Compatibility.h> // For std::unique_ptr<> | |
52 #include <Logging.h> | |
53 #include <OrthancException.h> | |
54 | |
55 // System | |
56 #include <boost/shared_ptr.hpp> | |
57 #include <boost/weak_ptr.hpp> | |
58 #include <boost/make_shared.hpp> | |
59 | |
60 #include <stdio.h> | |
61 | |
62 | |
63 namespace OrthancStone | |
64 { | |
65 boost::shared_ptr<RtViewerApp> RtViewerView::GetApp() | |
66 { | |
67 return app_.lock(); | |
68 } | |
69 | |
70 void RtViewerView::DisplayInfoText() | |
71 { | |
72 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); | |
73 ViewportController& controller = lock->GetController(); | |
74 Scene2D& scene = controller.GetScene(); | |
75 | |
76 // do not try to use stuff too early! | |
77 OrthancStone::ICompositor& compositor = lock->GetCompositor(); | |
78 | |
79 std::stringstream msg; | |
80 | |
81 for (std::map<std::string, std::string>::const_iterator kv = infoTextMap_.begin(); | |
82 kv != infoTextMap_.end(); ++kv) | |
83 { | |
84 msg << kv->first << " : " << kv->second << std::endl; | |
85 } | |
86 std::string msgS = msg.str(); | |
87 | |
88 TextSceneLayer* layerP = NULL; | |
89 if (scene.HasLayer(FIXED_INFOTEXT_LAYER_ZINDEX)) | |
90 { | |
91 TextSceneLayer& layer = dynamic_cast<TextSceneLayer&>( | |
92 scene.GetLayer(FIXED_INFOTEXT_LAYER_ZINDEX)); | |
93 layerP = &layer; | |
94 } | |
95 else | |
96 { | |
97 std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer); | |
98 layerP = layer.get(); | |
99 layer->SetColor(0, 255, 0); | |
100 layer->SetFontIndex(1); | |
101 layer->SetBorder(20); | |
102 layer->SetAnchor(BitmapAnchor_TopLeft); | |
103 //layer->SetPosition(0,0); | |
104 scene.SetLayer(FIXED_INFOTEXT_LAYER_ZINDEX, layer.release()); | |
105 } | |
106 // position the fixed info text in the upper right corner | |
107 layerP->SetText(msgS.c_str()); | |
108 double cX = compositor.GetCanvasWidth() * (-0.5); | |
109 double cY = compositor.GetCanvasHeight() * (-0.5); | |
110 scene.GetCanvasToSceneTransform().Apply(cX, cY); | |
111 layerP->SetPosition(cX, cY); | |
112 lock->Invalidate(); | |
113 } | |
114 | |
115 void RtViewerView::DisplayFloatingCtrlInfoText(const PointerEvent& e) | |
116 { | |
117 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); | |
118 ViewportController& controller = lock->GetController(); | |
119 Scene2D& scene = controller.GetScene(); | |
120 | |
121 ScenePoint2D p = e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform()); | |
122 | |
123 char buf[128]; | |
124 sprintf(buf, "S:(%0.02f,%0.02f) C:(%0.02f,%0.02f)", | |
125 p.GetX(), p.GetY(), | |
126 e.GetMainPosition().GetX(), e.GetMainPosition().GetY()); | |
127 | |
128 if (scene.HasLayer(FLOATING_INFOTEXT_LAYER_ZINDEX)) | |
129 { | |
130 TextSceneLayer& layer = | |
131 dynamic_cast<TextSceneLayer&>(scene.GetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX)); | |
132 layer.SetText(buf); | |
133 layer.SetPosition(p.GetX(), p.GetY()); | |
134 } | |
135 else | |
136 { | |
137 std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer); | |
138 layer->SetColor(0, 255, 0); | |
139 layer->SetText(buf); | |
140 layer->SetBorder(20); | |
141 layer->SetAnchor(BitmapAnchor_BottomCenter); | |
142 layer->SetPosition(p.GetX(), p.GetY()); | |
143 scene.SetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX, layer.release()); | |
144 } | |
145 } | |
146 | |
147 void RtViewerView::HideInfoText() | |
148 { | |
149 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); | |
150 ViewportController& controller = lock->GetController(); | |
151 Scene2D& scene = controller.GetScene(); | |
152 | |
153 scene.DeleteLayer(FLOATING_INFOTEXT_LAYER_ZINDEX); | |
154 } | |
155 | |
156 void RtViewerView::OnSceneTransformChanged( | |
157 const ViewportController::SceneTransformChanged& message) | |
158 { | |
159 DisplayInfoText(); | |
160 } | |
161 | |
162 void RtViewerView::Invalidate() | |
163 { | |
164 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); | |
165 lock->GetCompositor().FitContent(lock->GetController().GetScene()); | |
166 lock->Invalidate(); | |
167 } | |
168 | |
169 void RtViewerView::FitContent() | |
170 { | |
171 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); | |
172 lock->GetCompositor().FitContent(lock->GetController().GetScene()); | |
173 lock->Invalidate(); | |
174 } | |
175 | |
176 void RtViewerView::Scroll(int delta) | |
177 { | |
178 if (!planes_.empty()) | |
179 { | |
180 int next = 0; | |
181 int temp = static_cast<int>(currentPlane_) + delta; | |
182 | |
183 if (temp < 0) | |
184 { | |
185 next = 0; | |
186 } | |
187 else if (temp >= static_cast<int>(planes_.size())) | |
188 { | |
189 next = static_cast<unsigned int>(planes_.size()) - 1; | |
190 } | |
191 else | |
192 { | |
193 next = static_cast<size_t>(temp); | |
194 } | |
195 LOG(INFO) << "RtViewerView::Scroll(" << delta << ") --> slice is now = " << next; | |
196 | |
197 if (next != static_cast<int>(currentPlane_)) | |
198 { | |
199 currentPlane_ = next; | |
200 UpdateLayers(); | |
201 } | |
202 } | |
203 } | |
204 | |
205 void RtViewerView::RetrieveGeometry() | |
206 { | |
207 const VolumeImageGeometry& geometry = GetApp()->GetMainGeometry(); | |
208 | |
209 const unsigned int depth = geometry.GetProjectionDepth(projection_); | |
210 currentPlane_ = depth / 2; | |
211 | |
212 planes_.resize(depth); | |
213 | |
214 for (unsigned int z = 0; z < depth; z++) | |
215 { | |
216 planes_[z] = geometry.GetProjectionSlice(projection_, z); | |
217 } | |
218 | |
219 UpdateLayers(); | |
220 } | |
221 | |
222 void RtViewerView::UpdateLayers() | |
223 { | |
224 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); | |
225 | |
226 if (planes_.size() == 0) | |
227 { | |
228 RetrieveGeometry(); | |
229 } | |
230 | |
231 if (currentPlane_ < planes_.size()) | |
232 { | |
233 if (ctVolumeLayerSource_.get() != NULL) | |
234 { | |
235 ctVolumeLayerSource_->Update(planes_[currentPlane_]); | |
236 } | |
237 if (doseVolumeLayerSource_.get() != NULL) | |
238 { | |
239 doseVolumeLayerSource_->Update(planes_[currentPlane_]); | |
240 } | |
241 if (structLayerSource_.get() != NULL) | |
242 { | |
243 structLayerSource_->Update(planes_[currentPlane_]); | |
244 } | |
245 } | |
246 lock->Invalidate(); | |
247 } | |
248 | |
249 void RtViewerView::PrepareViewport() | |
250 { | |
251 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); | |
252 ViewportController& controller = lock->GetController(); | |
253 ICompositor& compositor = lock->GetCompositor(); | |
254 | |
255 // False means we do NOT let a hi-DPI aware desktop managedr treat this as a legacy application that requires | |
256 // scaling. | |
257 controller.FitContent(compositor.GetCanvasWidth(), compositor.GetCanvasHeight()); | |
258 | |
259 std::string ttf; | |
260 Orthanc::EmbeddedResources::GetFileResource(ttf, Orthanc::EmbeddedResources::UBUNTU_FONT); | |
261 compositor.SetFont(0, ttf, FONT_SIZE_0, Orthanc::Encoding_Latin1); | |
262 compositor.SetFont(1, ttf, FONT_SIZE_1, Orthanc::Encoding_Latin1); | |
263 } | |
264 | |
265 void RtViewerView::SetInfoDisplayMessage( | |
266 std::string key, std::string value) | |
267 { | |
268 if (value == "") | |
269 infoTextMap_.erase(key); | |
270 else | |
271 infoTextMap_[key] = value; | |
272 DisplayInfoText(); | |
273 } | |
274 | |
275 void RtViewerView::RegisterMessages() | |
276 { | |
277 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); | |
278 ViewportController& controller = lock->GetController(); | |
279 Register<ViewportController::SceneTransformChanged>(controller, &RtViewerView::OnSceneTransformChanged); | |
280 } | |
281 | |
282 void RtViewerView::CreateLayers(boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> ctLoader, | |
283 boost::shared_ptr<OrthancMultiframeVolumeLoader> doseLoader, | |
284 boost::shared_ptr<DicomVolumeImage> doseVolume, | |
285 boost::shared_ptr<DicomStructureSetLoader> rtstructLoader) | |
286 { | |
287 /** | |
288 Configure the CT | |
289 */ | |
290 std::unique_ptr<GrayscaleStyleConfigurator> style(new GrayscaleStyleConfigurator); | |
291 style->SetLinearInterpolation(true); | |
292 | |
293 this->SetCtVolumeSlicer(ctLoader, style.release()); | |
294 | |
295 { | |
296 std::string lut; | |
297 Orthanc::EmbeddedResources::GetFileResource(lut, Orthanc::EmbeddedResources::COLORMAP_HOT); | |
298 | |
299 std::unique_ptr<LookupTableStyleConfigurator> config(new LookupTableStyleConfigurator); | |
300 config->SetLookupTable(lut); | |
301 | |
302 boost::shared_ptr<DicomVolumeImageMPRSlicer> tmp(new DicomVolumeImageMPRSlicer(doseVolume)); | |
303 this->SetDoseVolumeSlicer(tmp, config.release()); | |
304 } | |
305 | |
306 this->SetStructureSet(rtstructLoader); | |
307 } | |
308 | |
309 void RtViewerView::SetCtVolumeSlicer(const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume, | |
310 OrthancStone::ILayerStyleConfigurator* style) | |
311 { | |
312 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); | |
313 ViewportController& controller = lock->GetController(); | |
314 Scene2D& scene = controller.GetScene(); | |
315 int depth = scene.GetMaxDepth() + 1; | |
316 | |
317 ctVolumeLayerSource_.reset(new OrthancStone::VolumeSceneLayerSource(viewport_, depth, volume)); | |
318 | |
319 if (style != NULL) | |
320 { | |
321 ctVolumeLayerSource_->SetConfigurator(style); | |
322 } | |
323 } | |
324 | |
325 void RtViewerView::SetDoseVolumeSlicer(const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume, | |
326 OrthancStone::ILayerStyleConfigurator* style) | |
327 { | |
328 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); | |
329 ViewportController& controller = lock->GetController(); | |
330 Scene2D& scene = controller.GetScene(); | |
331 int depth = scene.GetMaxDepth() + 1; | |
332 | |
333 doseVolumeLayerSource_.reset(new OrthancStone::VolumeSceneLayerSource(viewport_, depth, volume)); | |
334 | |
335 if (style != NULL) | |
336 { | |
337 doseVolumeLayerSource_->SetConfigurator(style); | |
338 } | |
339 } | |
340 | |
341 void RtViewerView::SetStructureSet(const boost::shared_ptr<OrthancStone::DicomStructureSetLoader>& volume) | |
342 { | |
343 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); | |
344 ViewportController& controller = lock->GetController(); | |
345 Scene2D& scene = controller.GetScene(); | |
346 int depth = scene.GetMaxDepth() + 1; | |
347 | |
348 structLayerSource_.reset(new OrthancStone::VolumeSceneLayerSource(viewport_, depth, volume)); | |
349 } | |
350 } |