Mercurial > hg > orthanc-stone
annotate Framework/dev.h @ 403:99e31898910e
IObservable.cpp
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sun, 11 Nov 2018 12:13:31 +0100 |
parents | 72355b637945 |
children | 3942123602ba |
rev | line source |
---|---|
102 | 1 /** |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
135
e2fe9352f240
upgrade to year 2018
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
121
diff
changeset
|
5 * Copyright (C) 2017-2018 Osimis S.A., Belgium |
102 | 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. | |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
16 * |
102 | 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 "Layers/FrameRenderer.h" | |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
25 #include "Layers/LineLayerRenderer.h" |
102 | 26 #include "Layers/SliceOutlineRenderer.h" |
27 #include "Toolbox/DownloadStack.h" | |
159
0a73d76333db
populating LinearAlgebra
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
158
diff
changeset
|
28 #include "Toolbox/GeometryToolbox.h" |
102 | 29 #include "Toolbox/OrthancSlicesLoader.h" |
30 #include "Volumes/ImageBuffer3D.h" | |
31 #include "Volumes/SlicedVolumeBase.h" | |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
32 #include "Widgets/SliceViewerWidget.h" |
102 | 33 |
212
5412adf19980
resort to OrthancFramework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
201
diff
changeset
|
34 #include <Core/Logging.h> |
5412adf19980
resort to OrthancFramework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
201
diff
changeset
|
35 #include <Core/Images/ImageProcessing.h> |
102 | 36 |
37 #include <boost/math/special_functions/round.hpp> | |
38 | |
39 | |
40 namespace OrthancStone | |
41 { | |
136
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
42 // TODO: Handle errors while loading |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
43 class OrthancVolumeImage : |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
44 public SlicedVolumeBase, |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
45 public OrthancStone::IObserver |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
46 { |
102 | 47 private: |
48 OrthancSlicesLoader loader_; | |
49 std::auto_ptr<ImageBuffer3D> image_; | |
50 std::auto_ptr<DownloadStack> downloadStack_; | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
51 bool computeRange_; |
136
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
52 size_t pendingSlices_; |
102 | 53 |
54 void ScheduleSliceDownload() | |
55 { | |
56 assert(downloadStack_.get() != NULL); | |
57 | |
58 unsigned int slice; | |
59 if (downloadStack_->Pop(slice)) | |
60 { | |
61 loader_.ScheduleLoadSliceImage(slice, SliceImageQuality_Jpeg90); | |
62 } | |
63 } | |
64 | |
65 | |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
66 static bool IsCompatible(const Slice& a, |
102 | 67 const Slice& b) |
68 { | |
69 if (!GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(), | |
70 b.GetGeometry().GetNormal())) | |
71 { | |
72 LOG(ERROR) << "Some slice in the volume image is not parallel to the others"; | |
73 return false; | |
74 } | |
75 | |
76 if (a.GetConverter().GetExpectedPixelFormat() != b.GetConverter().GetExpectedPixelFormat()) | |
77 { | |
78 LOG(ERROR) << "The pixel format changes across the slices of the volume image"; | |
79 return false; | |
80 } | |
81 | |
82 if (a.GetWidth() != b.GetWidth() || | |
83 a.GetHeight() != b.GetHeight()) | |
84 { | |
85 LOG(ERROR) << "The width/height of the slices change across the volume image"; | |
86 return false; | |
87 } | |
88 | |
158
a053ca7fa5c6
LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
138
diff
changeset
|
89 if (!LinearAlgebra::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) || |
a053ca7fa5c6
LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
138
diff
changeset
|
90 !LinearAlgebra::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY())) |
102 | 91 { |
92 LOG(ERROR) << "The pixel spacing of the slices change across the volume image"; | |
93 return false; | |
94 } | |
95 | |
96 return true; | |
97 } | |
98 | |
99 | |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
100 static double GetDistance(const Slice& a, |
102 | 101 const Slice& b) |
102 { | |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
103 return fabs(a.GetGeometry().ProjectAlongNormal(a.GetGeometry().GetOrigin()) - |
102 | 104 a.GetGeometry().ProjectAlongNormal(b.GetGeometry().GetOrigin())); |
105 } | |
106 | |
107 | |
266
c9cf95b49a86
removed OrthancSlicesLoader::ISliceLoaderObserver; now using standard messages instead
am@osimis.io
parents:
252
diff
changeset
|
108 void OnSliceGeometryReady(const OrthancSlicesLoader& loader) |
102 | 109 { |
110 if (loader.GetSliceCount() == 0) | |
111 { | |
112 LOG(ERROR) << "Empty volume image"; | |
113 SlicedVolumeBase::NotifyGeometryError(); | |
114 return; | |
115 } | |
116 | |
117 for (size_t i = 1; i < loader.GetSliceCount(); i++) | |
118 { | |
119 if (!IsCompatible(loader.GetSlice(0), loader.GetSlice(i))) | |
120 { | |
121 SlicedVolumeBase::NotifyGeometryError(); | |
122 return; | |
123 } | |
124 } | |
125 | |
126 double spacingZ; | |
127 | |
128 if (loader.GetSliceCount() > 1) | |
129 { | |
130 spacingZ = GetDistance(loader.GetSlice(0), loader.GetSlice(1)); | |
131 } | |
132 else | |
133 { | |
134 // This is a volume with one single slice: Choose a dummy | |
135 // z-dimension for voxels | |
136 spacingZ = 1; | |
137 } | |
120
063f7f3d9f14
fix 3d locations of the doses
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
119
diff
changeset
|
138 |
102 | 139 for (size_t i = 1; i < loader.GetSliceCount(); i++) |
140 { | |
158
a053ca7fa5c6
LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
138
diff
changeset
|
141 if (!LinearAlgebra::IsNear(spacingZ, GetDistance(loader.GetSlice(i - 1), loader.GetSlice(i)), |
a053ca7fa5c6
LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
138
diff
changeset
|
142 0.001 /* this is expressed in mm */)) |
102 | 143 { |
144 LOG(ERROR) << "The distance between successive slices is not constant in a volume image"; | |
145 SlicedVolumeBase::NotifyGeometryError(); | |
146 return; | |
147 } | |
148 } | |
149 | |
150 unsigned int width = loader.GetSlice(0).GetWidth(); | |
151 unsigned int height = loader.GetSlice(0).GetHeight(); | |
152 Orthanc::PixelFormat format = loader.GetSlice(0).GetConverter().GetExpectedPixelFormat(); | |
266
c9cf95b49a86
removed OrthancSlicesLoader::ISliceLoaderObserver; now using standard messages instead
am@osimis.io
parents:
252
diff
changeset
|
153 LOG(INFO) << "Creating a volume image of size " << width << "x" << height |
102 | 154 << "x" << loader.GetSliceCount() << " in " << Orthanc::EnumerationToString(format); |
155 | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
156 image_.reset(new ImageBuffer3D(format, width, height, loader.GetSliceCount(), computeRange_)); |
102 | 157 image_->SetAxialGeometry(loader.GetSlice(0).GetGeometry()); |
266
c9cf95b49a86
removed OrthancSlicesLoader::ISliceLoaderObserver; now using standard messages instead
am@osimis.io
parents:
252
diff
changeset
|
158 image_->SetVoxelDimensions(loader.GetSlice(0).GetPixelSpacingX(), |
102 | 159 loader.GetSlice(0).GetPixelSpacingY(), spacingZ); |
160 image_->Clear(); | |
266
c9cf95b49a86
removed OrthancSlicesLoader::ISliceLoaderObserver; now using standard messages instead
am@osimis.io
parents:
252
diff
changeset
|
161 |
102 | 162 downloadStack_.reset(new DownloadStack(loader.GetSliceCount())); |
136
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
163 pendingSlices_ = loader.GetSliceCount(); |
102 | 164 |
165 for (unsigned int i = 0; i < 4; i++) // Limit to 4 simultaneous downloads | |
166 { | |
167 ScheduleSliceDownload(); | |
168 } | |
169 | |
170 // TODO Check the DicomFrameConverter are constant | |
171 | |
172 SlicedVolumeBase::NotifyGeometryReady(); | |
173 } | |
174 | |
252 | 175 virtual void OnSliceImageReady(const OrthancSlicesLoader& loader, |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
176 unsigned int sliceIndex, |
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
177 const Slice& slice, |
378 | 178 const Orthanc::ImageAccessor& image, |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
179 SliceImageQuality quality) |
102 | 180 { |
181 { | |
182 ImageBuffer3D::SliceWriter writer(*image_, VolumeProjection_Axial, sliceIndex); | |
378 | 183 Orthanc::ImageProcessing::Copy(writer.GetAccessor(), image); |
102 | 184 } |
185 | |
399
885e1ebd315c
rename SliceChange as SliceContentChange
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
398
diff
changeset
|
186 SlicedVolumeBase::NotifySliceContentChange(sliceIndex, slice); |
136
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
187 |
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
188 if (pendingSlices_ == 1) |
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
189 { |
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
190 SlicedVolumeBase::NotifyVolumeReady(); |
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
191 pendingSlices_ = 0; |
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
192 } |
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
193 else if (pendingSlices_ > 1) |
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
194 { |
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
195 pendingSlices_ -= 1; |
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
196 } |
102 | 197 |
198 ScheduleSliceDownload(); | |
199 } | |
200 | |
266
c9cf95b49a86
removed OrthancSlicesLoader::ISliceLoaderObserver; now using standard messages instead
am@osimis.io
parents:
252
diff
changeset
|
201 virtual void HandleMessage(const IObservable& from, const IMessage& message) |
102 | 202 { |
266
c9cf95b49a86
removed OrthancSlicesLoader::ISliceLoaderObserver; now using standard messages instead
am@osimis.io
parents:
252
diff
changeset
|
203 switch (message.GetType()) |
c9cf95b49a86
removed OrthancSlicesLoader::ISliceLoaderObserver; now using standard messages instead
am@osimis.io
parents:
252
diff
changeset
|
204 { |
378 | 205 case MessageType_SliceLoader_GeometryReady: |
206 OnSliceGeometryReady(dynamic_cast<const OrthancSlicesLoader&>(from)); | |
207 break; | |
208 | |
209 case MessageType_SliceLoader_GeometryError: | |
210 LOG(ERROR) << "Unable to download a volume image"; | |
211 SlicedVolumeBase::NotifyGeometryError(); | |
212 break; | |
213 | |
214 case MessageType_SliceLoader_ImageReady: | |
215 { | |
216 const OrthancSlicesLoader::SliceImageReadyMessage& msg = | |
217 dynamic_cast<const OrthancSlicesLoader::SliceImageReadyMessage&>(message); | |
218 OnSliceImageReady(dynamic_cast<const OrthancSlicesLoader&>(from), | |
219 msg.GetSliceIndex(), | |
220 msg.GetSlice(), | |
221 msg.GetImage(), | |
222 msg.GetEffectiveQuality()); | |
223 break; | |
224 } | |
225 | |
226 case MessageType_SliceLoader_ImageError: | |
227 { | |
228 const OrthancSlicesLoader::SliceImageErrorMessage& msg = | |
229 dynamic_cast<const OrthancSlicesLoader::SliceImageErrorMessage&>(message); | |
230 LOG(ERROR) << "Cannot download slice " << msg.GetSliceIndex() << " in a volume image"; | |
231 ScheduleSliceDownload(); | |
232 break; | |
233 } | |
234 | |
235 default: | |
236 VLOG("unhandled message type" << message.GetType()); | |
266
c9cf95b49a86
removed OrthancSlicesLoader::ISliceLoaderObserver; now using standard messages instead
am@osimis.io
parents:
252
diff
changeset
|
237 } |
102 | 238 } |
239 | |
240 public: | |
251
192e6e349e69
first usage of new message system (in SDL only)
am@osimis.io
parents:
216
diff
changeset
|
241 OrthancVolumeImage(MessageBroker& broker, |
300
b4abaeb783b1
messaging refactoring almost complete: works fine in native
am@osimis.io
parents:
299
diff
changeset
|
242 OrthancApiClient& orthanc, |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
243 bool computeRange) : |
266
c9cf95b49a86
removed OrthancSlicesLoader::ISliceLoaderObserver; now using standard messages instead
am@osimis.io
parents:
252
diff
changeset
|
244 OrthancStone::IObserver(broker), |
c9cf95b49a86
removed OrthancSlicesLoader::ISliceLoaderObserver; now using standard messages instead
am@osimis.io
parents:
252
diff
changeset
|
245 loader_(broker, orthanc), |
136
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
246 computeRange_(computeRange), |
a06ad9d7406e
ISlicedVolume::NotifyVolumeReady
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
135
diff
changeset
|
247 pendingSlices_(0) |
102 | 248 { |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
249 // TODO: replace with new callables loader_.RegisterObserver(*this); |
102 | 250 } |
251 | |
252 void ScheduleLoadSeries(const std::string& seriesId) | |
253 { | |
254 loader_.ScheduleLoadSeries(seriesId); | |
255 } | |
256 | |
117
42c05a3baee3
loading multi-frame instances as 3D volumes
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
257 void ScheduleLoadInstance(const std::string& instanceId) |
102 | 258 { |
117
42c05a3baee3
loading multi-frame instances as 3D volumes
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
259 loader_.ScheduleLoadInstance(instanceId); |
42c05a3baee3
loading multi-frame instances as 3D volumes
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
260 } |
42c05a3baee3
loading multi-frame instances as 3D volumes
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
261 |
42c05a3baee3
loading multi-frame instances as 3D volumes
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
262 void ScheduleLoadFrame(const std::string& instanceId, |
42c05a3baee3
loading multi-frame instances as 3D volumes
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
263 unsigned int frame) |
42c05a3baee3
loading multi-frame instances as 3D volumes
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
264 { |
42c05a3baee3
loading multi-frame instances as 3D volumes
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
265 loader_.ScheduleLoadFrame(instanceId, frame); |
102 | 266 } |
267 | |
268 virtual size_t GetSliceCount() const | |
269 { | |
270 return loader_.GetSliceCount(); | |
271 } | |
272 | |
273 virtual const Slice& GetSlice(size_t index) const | |
274 { | |
275 return loader_.GetSlice(index); | |
276 } | |
277 | |
278 ImageBuffer3D& GetImage() const | |
279 { | |
280 if (image_.get() == NULL) | |
281 { | |
282 // The geometry is not ready yet | |
283 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
284 } | |
285 else | |
286 { | |
287 return *image_; | |
288 } | |
289 } | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
290 |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
291 bool FitWindowingToRange(RenderStyle& style, |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
292 const DicomFrameConverter& converter) const |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
293 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
294 if (image_.get() == NULL) |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
295 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
296 return false; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
297 } |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
298 else |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
299 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
300 return image_->FitWindowingToRange(style, converter); |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
301 } |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
302 } |
102 | 303 }; |
304 | |
305 | |
306 class VolumeImageGeometry | |
307 { | |
308 private: | |
309 unsigned int width_; | |
310 unsigned int height_; | |
311 size_t depth_; | |
312 double pixelSpacingX_; | |
313 double pixelSpacingY_; | |
314 double sliceThickness_; | |
110
53025eecbc95
renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
104
diff
changeset
|
315 CoordinateSystem3D reference_; |
102 | 316 DicomFrameConverter converter_; |
317 | |
318 double ComputeAxialThickness(const OrthancVolumeImage& volume) const | |
319 { | |
320 double thickness; | |
321 | |
322 size_t n = volume.GetSliceCount(); | |
323 if (n > 1) | |
324 { | |
325 const Slice& a = volume.GetSlice(0); | |
326 const Slice& b = volume.GetSlice(n - 1); | |
327 thickness = ((reference_.ProjectAlongNormal(b.GetGeometry().GetOrigin()) - | |
328 reference_.ProjectAlongNormal(a.GetGeometry().GetOrigin())) / | |
329 (static_cast<double>(n) - 1.0)); | |
330 } | |
331 else | |
332 { | |
333 thickness = volume.GetSlice(0).GetThickness(); | |
334 } | |
335 | |
336 if (thickness <= 0) | |
337 { | |
338 // The slices should have been sorted with increasing Z | |
339 // (along the normal) by the OrthancSlicesLoader | |
340 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
341 } | |
342 else | |
343 { | |
344 return thickness; | |
345 } | |
346 } | |
347 | |
348 void SetupAxial(const OrthancVolumeImage& volume) | |
349 { | |
350 const Slice& axial = volume.GetSlice(0); | |
351 | |
352 width_ = axial.GetWidth(); | |
353 height_ = axial.GetHeight(); | |
354 depth_ = volume.GetSliceCount(); | |
355 | |
356 pixelSpacingX_ = axial.GetPixelSpacingX(); | |
357 pixelSpacingY_ = axial.GetPixelSpacingY(); | |
358 sliceThickness_ = ComputeAxialThickness(volume); | |
359 | |
360 reference_ = axial.GetGeometry(); | |
361 } | |
362 | |
363 void SetupCoronal(const OrthancVolumeImage& volume) | |
364 { | |
365 const Slice& axial = volume.GetSlice(0); | |
366 double axialThickness = ComputeAxialThickness(volume); | |
367 | |
368 width_ = axial.GetWidth(); | |
369 height_ = volume.GetSliceCount(); | |
370 depth_ = axial.GetHeight(); | |
371 | |
372 pixelSpacingX_ = axial.GetPixelSpacingX(); | |
373 pixelSpacingY_ = axialThickness; | |
374 sliceThickness_ = axial.GetPixelSpacingY(); | |
375 | |
376 Vector origin = axial.GetGeometry().GetOrigin(); | |
377 origin += (static_cast<double>(volume.GetSliceCount() - 1) * | |
378 axialThickness * axial.GetGeometry().GetNormal()); | |
379 | |
110
53025eecbc95
renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
104
diff
changeset
|
380 reference_ = CoordinateSystem3D(origin, |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
381 axial.GetGeometry().GetAxisX(), |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
382 -axial.GetGeometry().GetNormal()); |
102 | 383 } |
384 | |
385 void SetupSagittal(const OrthancVolumeImage& volume) | |
386 { | |
387 const Slice& axial = volume.GetSlice(0); | |
388 double axialThickness = ComputeAxialThickness(volume); | |
389 | |
390 width_ = axial.GetHeight(); | |
391 height_ = volume.GetSliceCount(); | |
392 depth_ = axial.GetWidth(); | |
393 | |
394 pixelSpacingX_ = axial.GetPixelSpacingY(); | |
395 pixelSpacingY_ = axialThickness; | |
396 sliceThickness_ = axial.GetPixelSpacingX(); | |
397 | |
398 Vector origin = axial.GetGeometry().GetOrigin(); | |
399 origin += (static_cast<double>(volume.GetSliceCount() - 1) * | |
400 axialThickness * axial.GetGeometry().GetNormal()); | |
401 | |
110
53025eecbc95
renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
104
diff
changeset
|
402 reference_ = CoordinateSystem3D(origin, |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
403 axial.GetGeometry().GetAxisY(), |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
404 axial.GetGeometry().GetNormal()); |
102 | 405 } |
406 | |
407 public: | |
408 VolumeImageGeometry(const OrthancVolumeImage& volume, | |
409 VolumeProjection projection) | |
410 { | |
411 if (volume.GetSliceCount() == 0) | |
412 { | |
413 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
414 } | |
415 | |
416 converter_ = volume.GetSlice(0).GetConverter(); | |
417 | |
418 switch (projection) | |
419 { | |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
420 case VolumeProjection_Axial: |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
421 SetupAxial(volume); |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
422 break; |
102 | 423 |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
424 case VolumeProjection_Coronal: |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
425 SetupCoronal(volume); |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
426 break; |
102 | 427 |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
428 case VolumeProjection_Sagittal: |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
429 SetupSagittal(volume); |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
430 break; |
102 | 431 |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
432 default: |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
433 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); |
102 | 434 } |
435 } | |
436 | |
437 size_t GetSliceCount() const | |
438 { | |
439 return depth_; | |
440 } | |
441 | |
442 const Vector& GetNormal() const | |
443 { | |
444 return reference_.GetNormal(); | |
445 } | |
446 | |
447 bool LookupSlice(size_t& index, | |
110
53025eecbc95
renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
104
diff
changeset
|
448 const CoordinateSystem3D& slice) const |
102 | 449 { |
450 bool opposite; | |
451 if (!GeometryToolbox::IsParallelOrOpposite(opposite, | |
452 reference_.GetNormal(), | |
453 slice.GetNormal())) | |
454 { | |
455 return false; | |
456 } | |
457 | |
458 double z = (reference_.ProjectAlongNormal(slice.GetOrigin()) - | |
459 reference_.ProjectAlongNormal(reference_.GetOrigin())) / sliceThickness_; | |
460 | |
461 int s = static_cast<int>(boost::math::iround(z)); | |
462 | |
463 if (s < 0 || | |
464 s >= static_cast<int>(depth_)) | |
465 { | |
466 return false; | |
467 } | |
468 else | |
469 { | |
470 index = static_cast<size_t>(s); | |
471 return true; | |
472 } | |
473 } | |
474 | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
475 Slice* GetSlice(size_t slice) const |
102 | 476 { |
216 | 477 if (slice >= depth_) |
102 | 478 { |
479 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
480 } | |
481 else | |
482 { | |
110
53025eecbc95
renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
104
diff
changeset
|
483 CoordinateSystem3D origin(reference_.GetOrigin() + |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
484 static_cast<double>(slice) * sliceThickness_ * reference_.GetNormal(), |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
485 reference_.GetAxisX(), |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
486 reference_.GetAxisY()); |
102 | 487 |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
488 return new Slice(origin, pixelSpacingX_, pixelSpacingY_, sliceThickness_, |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
489 width_, height_, converter_); |
102 | 490 } |
491 } | |
492 }; | |
493 | |
494 | |
495 | |
398
d257ea56b7be
renamed DicomStructureSetRendererFactory as DicomStructureSetSlicer, VolumeImageSource as VolumeImageMPRSlicer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
396
diff
changeset
|
496 class VolumeImageMPRSlicer : |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
497 public IVolumeSlicer, |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
498 private ISlicedVolume::IObserver |
102 | 499 { |
500 private: | |
381
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
501 class RendererFactory : public LayerReadyMessage::IRendererFactory |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
502 { |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
503 private: |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
504 const Orthanc::ImageAccessor& frame_; |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
505 const Slice& slice_; |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
506 bool isFullQuality_; |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
507 |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
508 public: |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
509 RendererFactory(const Orthanc::ImageAccessor& frame, |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
510 const Slice& slice, |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
511 bool isFullQuality) : |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
512 frame_(frame), |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
513 slice_(slice), |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
514 isFullQuality_(isFullQuality) |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
515 { |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
516 } |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
517 |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
518 virtual ILayerRenderer* CreateRenderer() const |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
519 { |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
520 return FrameRenderer::CreateRenderer(frame_, slice_, isFullQuality_); |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
521 } |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
522 }; |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
523 |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
524 |
102 | 525 OrthancVolumeImage& volume_; |
526 std::auto_ptr<VolumeImageGeometry> axialGeometry_; | |
527 std::auto_ptr<VolumeImageGeometry> coronalGeometry_; | |
528 std::auto_ptr<VolumeImageGeometry> sagittalGeometry_; | |
529 | |
530 | |
531 bool IsGeometryReady() const | |
532 { | |
533 return axialGeometry_.get() != NULL; | |
534 } | |
535 | |
536 | |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
537 virtual void NotifyGeometryReady(const ISlicedVolume& volume) ORTHANC_OVERRIDE |
102 | 538 { |
396
ed7146fa2c98
rename ILayerSource as IVolumeSlicer, and OrthancFrameLayerSource as as DicomSeriesVolumeSlicer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
390
diff
changeset
|
539 // These 3 values are only used to speed up the IVolumeSlicer |
102 | 540 axialGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Axial)); |
541 coronalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Coronal)); | |
542 sagittalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Sagittal)); | |
543 | |
401
f1c769b3a5c2
start getting rid of VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
399
diff
changeset
|
544 EmitMessage(IVolumeSlicer::GeometryReadyMessage(*this)); |
102 | 545 } |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
546 |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
547 virtual void NotifyGeometryError(const ISlicedVolume& volume) ORTHANC_OVERRIDE |
102 | 548 { |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
549 EmitMessage(IVolumeSlicer::GeometryErrorMessage(*this)); |
102 | 550 } |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
551 |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
552 virtual void NotifyContentChange(const ISlicedVolume& volume) ORTHANC_OVERRIDE |
102 | 553 { |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
554 EmitMessage(IVolumeSlicer::ContentChangedMessage(*this)); |
102 | 555 } |
556 | |
399
885e1ebd315c
rename SliceChange as SliceContentChange
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
398
diff
changeset
|
557 virtual void NotifySliceContentChange(const ISlicedVolume& volume, |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
558 const size_t& sliceIndex, |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
559 const Slice& slice) ORTHANC_OVERRIDE |
102 | 560 { |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
561 //IVolumeSlicer::NotifySliceContentChange(slice); |
102 | 562 |
563 // TODO Improve this? | |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
564 EmitMessage(IVolumeSlicer::ContentChangedMessage(*this)); |
102 | 565 } |
566 | |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
567 virtual void NotifyVolumeReady(const ISlicedVolume& volume) ORTHANC_OVERRIDE |
138 | 568 { |
569 } | |
102 | 570 |
571 const VolumeImageGeometry& GetProjectionGeometry(VolumeProjection projection) | |
572 { | |
573 if (!IsGeometryReady()) | |
574 { | |
575 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
576 } | |
577 | |
578 switch (projection) | |
579 { | |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
580 case VolumeProjection_Axial: |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
581 return *axialGeometry_; |
102 | 582 |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
583 case VolumeProjection_Sagittal: |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
584 return *sagittalGeometry_; |
102 | 585 |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
586 case VolumeProjection_Coronal: |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
587 return *coronalGeometry_; |
102 | 588 |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
589 default: |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
590 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
102 | 591 } |
592 } | |
593 | |
594 | |
595 bool DetectProjection(VolumeProjection& projection, | |
110
53025eecbc95
renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
104
diff
changeset
|
596 const CoordinateSystem3D& viewportSlice) |
102 | 597 { |
598 bool isOpposite; // Ignored | |
599 | |
600 if (GeometryToolbox::IsParallelOrOpposite(isOpposite, | |
601 viewportSlice.GetNormal(), | |
602 axialGeometry_->GetNormal())) | |
603 { | |
604 projection = VolumeProjection_Axial; | |
605 return true; | |
606 } | |
607 else if (GeometryToolbox::IsParallelOrOpposite(isOpposite, | |
608 viewportSlice.GetNormal(), | |
609 sagittalGeometry_->GetNormal())) | |
610 { | |
611 projection = VolumeProjection_Sagittal; | |
612 return true; | |
613 } | |
614 else if (GeometryToolbox::IsParallelOrOpposite(isOpposite, | |
615 viewportSlice.GetNormal(), | |
616 coronalGeometry_->GetNormal())) | |
617 { | |
618 projection = VolumeProjection_Coronal; | |
619 return true; | |
620 } | |
621 else | |
622 { | |
623 return false; | |
624 } | |
625 } | |
626 | |
627 | |
628 public: | |
398
d257ea56b7be
renamed DicomStructureSetRendererFactory as DicomStructureSetSlicer, VolumeImageSource as VolumeImageMPRSlicer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
396
diff
changeset
|
629 VolumeImageMPRSlicer(MessageBroker& broker, |
d257ea56b7be
renamed DicomStructureSetRendererFactory as DicomStructureSetSlicer, VolumeImageSource as VolumeImageMPRSlicer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
396
diff
changeset
|
630 OrthancVolumeImage& volume) : |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
631 IVolumeSlicer(broker), |
102 | 632 volume_(volume) |
633 { | |
634 volume_.Register(*this); | |
635 } | |
636 | |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
637 virtual ~VolumeImageMPRSlicer() |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
638 { |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
639 } |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
640 |
102 | 641 virtual bool GetExtent(std::vector<Vector>& points, |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
642 const CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE |
102 | 643 { |
644 VolumeProjection projection; | |
645 | |
646 if (!IsGeometryReady() || | |
647 !DetectProjection(projection, viewportSlice)) | |
648 { | |
649 return false; | |
650 } | |
651 else | |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
652 { |
102 | 653 // As the slices of the volumic image are arranged in a box, |
654 // we only consider one single reference slice (the one with index 0). | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
655 std::auto_ptr<Slice> slice(GetProjectionGeometry(projection).GetSlice(0)); |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
656 slice->GetExtent(points); |
102 | 657 |
658 return true; | |
659 } | |
660 } | |
661 | |
662 | |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
663 virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE |
102 | 664 { |
665 VolumeProjection projection; | |
666 | |
667 if (IsGeometryReady() && | |
668 DetectProjection(projection, viewportSlice)) | |
669 { | |
670 const VolumeImageGeometry& geometry = GetProjectionGeometry(projection); | |
671 | |
672 size_t closest; | |
673 | |
674 if (geometry.LookupSlice(closest, viewportSlice)) | |
675 { | |
676 bool isFullQuality = true; // TODO | |
677 | |
678 std::auto_ptr<Orthanc::Image> frame; | |
679 | |
680 { | |
681 ImageBuffer3D::SliceReader reader(volume_.GetImage(), projection, closest); | |
682 | |
683 // TODO Transfer ownership if non-axial, to avoid memcpy | |
684 frame.reset(Orthanc::Image::Clone(reader.GetAccessor())); | |
685 } | |
686 | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
687 std::auto_ptr<Slice> slice(geometry.GetSlice(closest)); |
381
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
688 |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
689 RendererFactory factory(*frame, *slice, isFullQuality); |
401
f1c769b3a5c2
start getting rid of VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
399
diff
changeset
|
690 |
f1c769b3a5c2
start getting rid of VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
399
diff
changeset
|
691 EmitMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice->GetGeometry())); |
102 | 692 return; |
693 } | |
694 } | |
695 | |
696 // Error | |
121
e66b2c757790
displaying rt-struct
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
120
diff
changeset
|
697 CoordinateSystem3D slice; |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
698 EmitMessage(IVolumeSlicer::LayerErrorMessage(*this, slice)); |
102 | 699 } |
700 }; | |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
701 |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
702 |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
703 class VolumeImageInteractor : |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
704 public IWorldSceneInteractor, |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
705 protected ISlicedVolume::IObserver |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
706 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
707 private: |
388
20f149669c1f
renamed LayerWidget as SliceViewerWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
381
diff
changeset
|
708 SliceViewerWidget& widget_; |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
709 VolumeProjection projection_; |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
710 std::auto_ptr<VolumeImageGeometry> slices_; |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
711 size_t slice_; |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
712 |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
713 protected: |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
714 virtual void NotifyGeometryReady(const ISlicedVolume& volume) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
715 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
716 if (slices_.get() == NULL) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
717 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
718 const OrthancVolumeImage& image = dynamic_cast<const OrthancVolumeImage&>(volume); |
120
063f7f3d9f14
fix 3d locations of the doses
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
119
diff
changeset
|
719 |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
720 slices_.reset(new VolumeImageGeometry(image, projection_)); |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
721 SetSlice(slices_->GetSliceCount() / 2); |
120
063f7f3d9f14
fix 3d locations of the doses
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
119
diff
changeset
|
722 |
330 | 723 widget_.FitContent(); |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
724 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
725 } |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
726 |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
727 virtual void NotifyGeometryError(const ISlicedVolume& volume) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
728 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
729 } |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
730 |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
731 virtual void NotifyContentChange(const ISlicedVolume& volume) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
732 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
733 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
734 |
399
885e1ebd315c
rename SliceChange as SliceContentChange
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
398
diff
changeset
|
735 virtual void NotifySliceContentChange(const ISlicedVolume& volume, |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
736 const size_t& sliceIndex, |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
737 const Slice& slice) |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
738 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
739 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
740 |
138 | 741 virtual void NotifyVolumeReady(const ISlicedVolume& volume) |
742 { | |
743 } | |
744 | |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
745 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
746 const ViewportGeometry& view, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
747 MouseButton button, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
748 double x, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
749 double y, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
750 IStatusBar* statusBar) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
751 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
752 return NULL; |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
753 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
754 |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
755 virtual void MouseOver(CairoContext& context, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
756 WorldSceneWidget& widget, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
757 const ViewportGeometry& view, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
758 double x, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
759 double y, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
760 IStatusBar* statusBar) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
761 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
762 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
763 |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
764 virtual void MouseWheel(WorldSceneWidget& widget, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
765 MouseWheelDirection direction, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
766 KeyboardModifiers modifiers, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
767 IStatusBar* statusBar) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
768 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
769 int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1); |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
770 |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
771 switch (direction) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
772 { |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
773 case MouseWheelDirection_Up: |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
774 OffsetSlice(-scale); |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
775 break; |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
776 |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
777 case MouseWheelDirection_Down: |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
778 OffsetSlice(scale); |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
779 break; |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
780 |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
781 default: |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
782 break; |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
783 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
784 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
785 |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
786 virtual void KeyPressed(WorldSceneWidget& widget, |
327 | 787 KeyboardKeys key, |
788 char keyChar, | |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
789 KeyboardModifiers modifiers, |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
790 IStatusBar* statusBar) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
791 { |
327 | 792 switch (keyChar) |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
793 { |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
794 case 's': |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
795 widget.FitContent(); |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
796 break; |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
797 |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
798 default: |
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
799 break; |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
800 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
801 } |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
802 |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
803 public: |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
804 VolumeImageInteractor(OrthancVolumeImage& volume, |
388
20f149669c1f
renamed LayerWidget as SliceViewerWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
381
diff
changeset
|
805 SliceViewerWidget& widget, |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
806 VolumeProjection projection) : |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
807 widget_(widget), |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
808 projection_(projection) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
809 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
810 volume.Register(*this); |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
811 widget.SetInteractor(*this); |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
812 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
813 |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
814 bool IsGeometryReady() const |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
815 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
816 return slices_.get() != NULL; |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
817 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
818 |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
819 size_t GetSliceCount() const |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
820 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
821 if (slices_.get() == NULL) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
822 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
823 return 0; |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
824 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
825 else |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
826 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
827 return slices_->GetSliceCount(); |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
828 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
829 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
830 |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
831 void OffsetSlice(int offset) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
832 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
833 if (slices_.get() != NULL) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
834 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
835 int slice = static_cast<int>(slice_) + offset; |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
836 |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
837 if (slice < 0) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
838 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
839 slice = 0; |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
840 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
841 |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
842 if (slice >= static_cast<int>(slices_->GetSliceCount())) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
843 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
844 slice = slices_->GetSliceCount() - 1; |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
845 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
846 |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
847 if (slice != static_cast<int>(slice_)) |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
848 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
849 SetSlice(slice); |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
850 } |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
851 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
852 } |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
853 |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
854 void SetSlice(size_t slice) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
855 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
856 if (slices_.get() != NULL) |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
857 { |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
858 slice_ = slice; |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
859 |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
860 std::auto_ptr<Slice> tmp(slices_->GetSlice(slice_)); |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
117
diff
changeset
|
861 widget_.SetSlice(tmp->GetGeometry()); |
104
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
862 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
863 } |
eccd64f8e297
VolumeImageInteractor
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
102
diff
changeset
|
864 }; |
112
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
865 |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
866 |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
867 |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
868 class ReferenceLineSource : public IVolumeSlicer |
112
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
869 { |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
870 private: |
381
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
871 class RendererFactory : public LayerReadyMessage::IRendererFactory |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
872 { |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
873 private: |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
874 double x1_; |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
875 double y1_; |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
876 double x2_; |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
877 double y2_; |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
878 const CoordinateSystem3D& slice_; |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
879 |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
880 public: |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
881 RendererFactory(double x1, |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
882 double y1, |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
883 double x2, |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
884 double y2, |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
885 const CoordinateSystem3D& slice) : |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
886 x1_(x1), |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
887 y1_(y1), |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
888 x2_(x2), |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
889 y2_(y2), |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
890 slice_(slice) |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
891 { |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
892 } |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
893 |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
894 virtual ILayerRenderer* CreateRenderer() const |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
895 { |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
896 return new LineLayerRenderer(x1_, y1_, x2_, y2_, slice_); |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
897 } |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
898 }; |
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
899 |
388
20f149669c1f
renamed LayerWidget as SliceViewerWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
381
diff
changeset
|
900 SliceViewerWidget& otherPlane_; |
112
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
901 |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
902 public: |
390
0cb925325470
renamed SiblingSliceLocation as ReferenceLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
388
diff
changeset
|
903 ReferenceLineSource(MessageBroker& broker, |
0cb925325470
renamed SiblingSliceLocation as ReferenceLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
388
diff
changeset
|
904 SliceViewerWidget& otherPlane) : |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
905 IVolumeSlicer(broker), |
112
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
906 otherPlane_(otherPlane) |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
907 { |
401
f1c769b3a5c2
start getting rid of VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
399
diff
changeset
|
908 EmitMessage(IVolumeSlicer::GeometryReadyMessage(*this)); |
112
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
909 } |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
910 |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
911 virtual bool GetExtent(std::vector<Vector>& points, |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
912 const CoordinateSystem3D& viewportSlice) |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
913 { |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
914 return false; |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
915 } |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
916 |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
917 virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice) |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
918 { |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
919 Slice reference(viewportSlice, 0.001); |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
920 |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
921 Vector p, d; |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
922 |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
923 const CoordinateSystem3D& slice = otherPlane_.GetSlice(); |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
924 |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
925 // Compute the line of intersection between the two slices |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
926 if (!GeometryToolbox::IntersectTwoPlanes(p, d, |
112
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
927 slice.GetOrigin(), slice.GetNormal(), |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
928 viewportSlice.GetOrigin(), viewportSlice.GetNormal())) |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
929 { |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
930 // The two slice are parallel, don't try and display the intersection |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
931 EmitMessage(IVolumeSlicer::LayerErrorMessage(*this, reference.GetGeometry())); |
112
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
932 } |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
933 else |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
934 { |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
935 double x1, y1, x2, y2; |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
936 viewportSlice.ProjectPoint(x1, y1, p); |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
937 viewportSlice.ProjectPoint(x2, y2, p + 1000.0 * d); |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
938 |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
939 const Extent2D extent = otherPlane_.GetSceneExtent(); |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
940 |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
941 if (GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2, |
112
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
942 x1, y1, x2, y2, |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
943 extent.GetX1(), extent.GetY1(), |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
944 extent.GetX2(), extent.GetY2())) |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
945 { |
381
19bd222283ae
uncoupling LayerReadyMessage from the creation of the renderer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
380
diff
changeset
|
946 RendererFactory factory(x1, y1, x2, y2, slice); |
401
f1c769b3a5c2
start getting rid of VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
399
diff
changeset
|
947 EmitMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, reference.GetGeometry())); |
112
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
948 } |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
949 else |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
950 { |
380
ba5ad93f935a
ILayerSource::LayerErrorMessage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
378
diff
changeset
|
951 // Error: Parallel slices |
402
72355b637945
removed VolumeSlicerBase
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
401
diff
changeset
|
952 EmitMessage(IVolumeSlicer::LayerErrorMessage(*this, reference.GetGeometry())); |
112
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
953 } |
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
954 } |
318
3a4ca166fafa
ImageAccessor refactoring + implemented Image Cache in SmartLoader
am@osimis.io
parents:
300
diff
changeset
|
955 } |
112
948f86e61e83
start of SliceLocationSource
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
956 }; |
102 | 957 } |