comparison Samples/Common/RtViewerApp.cpp @ 1404:3e644f6fadd4

Three-viewport is now OK in SDL and Wasm
author Benjamin Golinvaux <bgo@osimis.io>
date Wed, 29 Apr 2020 22:06:24 +0200
parents
children 07fac4fdbe07
comparison
equal deleted inserted replaced
1395:62dc0d737e7b 1404:3e644f6fadd4
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 // Sample app
22 #include "RtViewerApp.h"
23 #include "RtViewerView.h"
24 #include "SampleHelpers.h"
25
26 // Stone of Orthanc
27 #include <Framework/StoneInitialization.h>
28 #include <Framework/Scene2D/CairoCompositor.h>
29 #include <Framework/Scene2D/ColorTextureSceneLayer.h>
30 #include <Framework/Scene2D/OpenGLCompositor.h>
31 #include <Framework/Scene2D/PanSceneTracker.h>
32 #include <Framework/Scene2D/ZoomSceneTracker.h>
33 #include <Framework/Scene2D/RotateSceneTracker.h>
34
35 #include <Framework/Scene2DViewport/UndoStack.h>
36 #include <Framework/Scene2DViewport/CreateLineMeasureTracker.h>
37 #include <Framework/Scene2DViewport/CreateAngleMeasureTracker.h>
38 #include <Framework/Scene2DViewport/IFlexiblePointerTracker.h>
39 #include <Framework/Scene2DViewport/MeasureTool.h>
40 #include <Framework/Scene2DViewport/PredeclaredTypes.h>
41 #include <Framework/Volumes/VolumeSceneLayerSource.h>
42
43 #include <Framework/Oracle/GetOrthancWebViewerJpegCommand.h>
44 #include <Framework/Scene2D/GrayscaleStyleConfigurator.h>
45 #include <Framework/Scene2D/LookupTableStyleConfigurator.h>
46 #include <Framework/Volumes/DicomVolumeImageMPRSlicer.h>
47 #include <Framework/StoneException.h>
48
49 // Orthanc
50 #include <Core/Logging.h>
51 #include <Core/OrthancException.h>
52
53 // System
54 #include <boost/shared_ptr.hpp>
55 #include <boost/weak_ptr.hpp>
56 #include <boost/make_shared.hpp>
57
58 #include <stdio.h>
59
60
61 namespace OrthancStone
62 {
63 const char* RtViewerGuiToolToString(size_t i)
64 {
65 static const char* descs[] = {
66 "RtViewerGuiTool_Rotate",
67 "RtViewerGuiTool_Pan",
68 "RtViewerGuiTool_Zoom",
69 "RtViewerGuiTool_LineMeasure",
70 "RtViewerGuiTool_CircleMeasure",
71 "RtViewerGuiTool_AngleMeasure",
72 "RtViewerGuiTool_EllipseMeasure",
73 "RtViewerGuiTool_LAST"
74 };
75 if (i >= RtViewerGuiTool_LAST)
76 {
77 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Wrong tool index");
78 }
79 return descs[i];
80 }
81
82 void RtViewerApp::SelectNextTool()
83 {
84 currentTool_ = static_cast<RtViewerGuiTool>(currentTool_ + 1);
85 if (currentTool_ == RtViewerGuiTool_LAST)
86 currentTool_ = static_cast<RtViewerGuiTool>(0);;
87 printf("Current tool is now: %s\n", RtViewerGuiToolToString(currentTool_));
88 }
89
90 void RtViewerApp::InvalidateAllViewports()
91 {
92 for (size_t i = 0; i < views_.size(); ++i)
93 {
94 views_[i]->Invalidate();
95 }
96 }
97
98 const VolumeImageGeometry& RtViewerApp::GetMainGeometry()
99 {
100 ORTHANC_ASSERT(geometryProvider_.get() != NULL);
101 ORTHANC_ASSERT(geometryProvider_->HasGeometry());
102 const VolumeImageGeometry& geometry = geometryProvider_->GetImageGeometry();
103 return geometry;
104 }
105
106 RtViewerApp::RtViewerApp()
107 : currentTool_(RtViewerGuiTool_Rotate)
108 , undoStack_(new UndoStack)
109 {
110 // Create the volumes that will be filled later on
111 ctVolume_ = boost::make_shared<DicomVolumeImage>();
112 doseVolume_ = boost::make_shared<DicomVolumeImage>();
113 }
114
115 boost::shared_ptr<RtViewerApp> RtViewerApp::Create()
116 {
117 boost::shared_ptr<RtViewerApp> thisOne(new RtViewerApp());
118 return thisOne;
119 }
120
121 void RtViewerApp::DisableTracker()
122 {
123 if (activeTracker_)
124 {
125 activeTracker_->Cancel();
126 activeTracker_.reset();
127 }
128 }
129
130 void RtViewerApp::CreateView(const std::string& canvasId, VolumeProjection projection)
131 {
132 boost::shared_ptr<RtViewerView>
133 view(new RtViewerView(shared_from_this(), canvasId, projection));
134
135 view->RegisterMessages();
136
137 view->CreateLayers(ctLoader_, doseLoader_, doseVolume_, rtstructLoader_);
138
139 views_.push_back(view);
140 }
141
142 void RtViewerApp::CreateLoaders()
143 {
144 // the viewport hosts the scene
145 {
146 // "true" means use progressive quality (jpeg 50 --> jpeg 90 --> 16-bit raw)
147 // "false" means only using hi quality
148 // TODO: add flag for quality
149 ctLoader_ = OrthancSeriesVolumeProgressiveLoader::Create(*loadersContext_, ctVolume_, true);
150
151 // we need to store the CT loader to ask from geometry details later on when geometry is loaded
152 geometryProvider_ = ctLoader_;
153
154 doseLoader_ = OrthancMultiframeVolumeLoader::Create(*loadersContext_, doseVolume_);
155 rtstructLoader_ = DicomStructureSetLoader::Create(*loadersContext_);
156 }
157
158 /**
159 Register for notifications issued by the loaders
160 */
161
162 Register<DicomVolumeImage::GeometryReadyMessage>
163 (*ctLoader_, &RtViewerApp::HandleGeometryReady);
164
165 Register<OrthancSeriesVolumeProgressiveLoader::VolumeImageReadyInHighQuality>
166 (*ctLoader_, &RtViewerApp::HandleCTLoaded);
167
168 Register<DicomVolumeImage::ContentUpdatedMessage>
169 (*ctLoader_, &RtViewerApp::HandleCTContentUpdated);
170
171 Register<DicomVolumeImage::ContentUpdatedMessage>
172 (*doseLoader_, &RtViewerApp::HandleDoseLoaded);
173
174 Register<DicomStructureSetLoader::StructuresReady>
175 (*rtstructLoader_, &RtViewerApp::HandleStructuresReady);
176
177 Register<DicomStructureSetLoader::StructuresUpdated>
178 (*rtstructLoader_, &RtViewerApp::HandleStructuresUpdated);
179 }
180
181 void RtViewerApp::StartLoaders()
182 {
183 ORTHANC_ASSERT(HasArgument("ctseries") && HasArgument("rtdose") && HasArgument("rtstruct"));
184
185 LOG(INFO) << "About to load:";
186 LOG(INFO) << " CT : " << GetArgument("ctseries");
187 LOG(INFO) << " RTDOSE : " << GetArgument("rtdose");
188 LOG(INFO) << " RTSTRUCT : " << GetArgument("rtstruct");
189 ctLoader_->LoadSeries(GetArgument("ctseries"));
190 doseLoader_->LoadInstance(GetArgument("rtdose"));
191 rtstructLoader_->LoadInstanceFullVisibility(GetArgument("rtstruct"));
192 }
193
194 void RtViewerApp::HandleGeometryReady(const DicomVolumeImage::GeometryReadyMessage& message)
195 {
196 for (size_t i = 0; i < views_.size(); ++i)
197 {
198 views_[i]->RetrieveGeometry();
199 }
200 FitContent();
201 UpdateLayersInAllViews();
202 }
203
204 void RtViewerApp::FitContent()
205 {
206 for (size_t i = 0; i < views_.size(); ++i)
207 {
208 views_[i]->FitContent();
209 }
210 }
211
212 void RtViewerApp::UpdateLayersInAllViews()
213 {
214 for (size_t i = 0; i < views_.size(); ++i)
215 {
216 views_[i]->UpdateLayers();
217 }
218 }
219
220 void RtViewerApp::HandleCTLoaded(const OrthancSeriesVolumeProgressiveLoader::VolumeImageReadyInHighQuality& message)
221 {
222 for (size_t i = 0; i < views_.size(); ++i)
223 {
224 views_[i]->RetrieveGeometry();
225 }
226 UpdateLayersInAllViews();
227 }
228
229 void RtViewerApp::HandleCTContentUpdated(const DicomVolumeImage::ContentUpdatedMessage& message)
230 {
231 UpdateLayersInAllViews();
232 }
233
234 void RtViewerApp::HandleDoseLoaded(const DicomVolumeImage::ContentUpdatedMessage& message)
235 {
236 //TODO: compute dose extent, with outlier rejection
237 UpdateLayersInAllViews();
238 }
239
240 void RtViewerApp::HandleStructuresReady(const DicomStructureSetLoader::StructuresReady& message)
241 {
242 UpdateLayersInAllViews();
243 }
244
245 void RtViewerApp::HandleStructuresUpdated(const DicomStructureSetLoader::StructuresUpdated& message)
246 {
247 UpdateLayersInAllViews();
248 }
249
250 void RtViewerApp::SetArgument(const std::string& key, const std::string& value)
251 {
252 if (key == "loglevel")
253 OrthancStoneHelpers::SetLogLevel(value);
254 else
255 arguments_[key] = value;
256 }
257
258 const std::string& RtViewerApp::GetArgument(const std::string& key) const
259 {
260 ORTHANC_ASSERT(HasArgument(key));
261 return arguments_.at(key);
262 }
263
264 bool RtViewerApp::HasArgument(const std::string& key) const
265 {
266 return (arguments_.find(key) != arguments_.end());
267 }
268 }
269