comparison Samples/Sdl/Loader.cpp @ 782:b24c208fa953

VolumeImageReslicer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 27 May 2019 14:21:04 +0200
parents 2bb72826fa3f
children cd13a062c9bd
comparison
equal deleted inserted replaced
781:2bb72826fa3f 782:b24c208fa953
65 { 65 {
66 } 66 }
67 67
68 virtual uint64_t GetRevision() const = 0; 68 virtual uint64_t GetRevision() const = 0;
69 69
70 virtual ISceneLayer* CreateFromImage(const Orthanc::ImageAccessor& image) const = 0; 70 virtual TextureBaseSceneLayer* CreateTextureFromImage(const Orthanc::ImageAccessor& image) const = 0;
71 71
72 virtual ISceneLayer* CreateFromDicomImage(const Orthanc::ImageAccessor& frame, 72 virtual TextureBaseSceneLayer* CreateTextureFromDicom(const Orthanc::ImageAccessor& frame,
73 const DicomInstanceParameters& parameters) const = 0; 73 const DicomInstanceParameters& parameters) const = 0;
74 74
75 virtual void ApplyStyle(ISceneLayer& layer) const = 0; 75 virtual void ApplyStyle(ISceneLayer& layer) const = 0;
76 }; 76 };
77 77
78 78
125 virtual uint64_t GetRevision() const 125 virtual uint64_t GetRevision() const
126 { 126 {
127 return revision_; 127 return revision_;
128 } 128 }
129 129
130 virtual ISceneLayer* CreateFromImage(const Orthanc::ImageAccessor& image) const 130 virtual TextureBaseSceneLayer* CreateTextureFromImage(const Orthanc::ImageAccessor& image) const
131 { 131 {
132 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 132 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
133 } 133 }
134 134
135 virtual ISceneLayer* CreateFromDicomImage(const Orthanc::ImageAccessor& frame, 135 virtual TextureBaseSceneLayer* CreateTextureFromDicom(const Orthanc::ImageAccessor& frame,
136 const DicomInstanceParameters& parameters) const 136 const DicomInstanceParameters& parameters) const
137 { 137 {
138 return parameters.CreateLookupTableTexture(frame); 138 return parameters.CreateLookupTableTexture(frame);
139 } 139 }
140 140
141 virtual void ApplyStyle(ISceneLayer& layer) const 141 virtual void ApplyStyle(ISceneLayer& layer) const
173 virtual uint64_t GetRevision() const 173 virtual uint64_t GetRevision() const
174 { 174 {
175 return revision_; 175 return revision_;
176 } 176 }
177 177
178 virtual ISceneLayer* CreateFromImage(const Orthanc::ImageAccessor& image) const 178 virtual TextureBaseSceneLayer* CreateTextureFromImage(const Orthanc::ImageAccessor& image) const
179 { 179 {
180 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 180 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
181 } 181 }
182 182
183 virtual ISceneLayer* CreateFromDicomImage(const Orthanc::ImageAccessor& frame, 183 virtual TextureBaseSceneLayer* CreateTextureFromDicom(const Orthanc::ImageAccessor& frame,
184 const DicomInstanceParameters& parameters) const 184 const DicomInstanceParameters& parameters) const
185 { 185 {
186 return parameters.CreateTexture(frame); 186 return parameters.CreateTexture(frame);
187 } 187 }
188 188
189 virtual void ApplyStyle(ISceneLayer& layer) const 189 virtual void ApplyStyle(ISceneLayer& layer) const
207 virtual bool HasGeometry() const = 0; 207 virtual bool HasGeometry() const = 0;
208 208
209 virtual const ImageBuffer3D& GetPixelData() const = 0; 209 virtual const ImageBuffer3D& GetPixelData() const = 0;
210 210
211 virtual const VolumeImageGeometry& GetGeometry() const = 0; 211 virtual const VolumeImageGeometry& GetGeometry() const = 0;
212
213 virtual bool HasDicomParameters() const = 0;
214
215 virtual const DicomInstanceParameters& GetDicomParameters() const = 0;
212 }; 216 };
213 217
214 218
215 class IVolumeSlicer : public boost::noncopyable 219 class IVolumeSlicer : public boost::noncopyable
216 { 220 {
230 // This call can take some time 234 // This call can take some time
231 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator, // possibly absent 235 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator, // possibly absent
232 const CoordinateSystem3D& cuttingPlane) = 0; 236 const CoordinateSystem3D& cuttingPlane) = 0;
233 }; 237 };
234 238
239
240 class InvalidSlice : public IExtractedSlice
241 {
242 public:
243 virtual bool IsValid()
244 {
245 return false;
246 }
247
248 virtual uint64_t GetRevision()
249 {
250 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
251 }
252
253 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator,
254 const CoordinateSystem3D& cuttingPlane)
255 {
256 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
257 }
258 };
259
260
235 virtual ~IVolumeSlicer() 261 virtual ~IVolumeSlicer()
236 { 262 {
237 } 263 }
238 264
239 virtual bool HasVolumeImage() const = 0; 265 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) = 0;
240
241 virtual const IVolumeImage& GetVolumeImage() const = 0;
242
243 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const = 0;
244 }; 266 };
245 267
246 268
247 class InvalidExtractedSlice : public IVolumeSlicer::IExtractedSlice
248 {
249 public:
250 virtual bool IsValid()
251 {
252 return false;
253 }
254
255 virtual uint64_t GetRevision()
256 {
257 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
258 }
259
260 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator,
261 const CoordinateSystem3D& cuttingPlane)
262 {
263 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
264 }
265 };
266
267
268 class DicomVolumeImageOrthogonalSlice : public IVolumeSlicer::IExtractedSlice 269 class DicomVolumeImageOrthogonalSlice : public IVolumeSlicer::IExtractedSlice
269 { 270 {
270 private: 271 private:
271 const ImageBuffer3D& image_; 272 const IVolumeImage& volume_;
272 const VolumeImageGeometry& geometry_; 273 bool valid_;
273 bool valid_; 274 VolumeProjection projection_;
274 VolumeProjection projection_; 275 unsigned int sliceIndex_;
275 unsigned int sliceIndex_;
276 276
277 void CheckValid() const 277 void CheckValid() const
278 { 278 {
279 if (!valid_) 279 if (!valid_)
280 { 280 {
284 284
285 protected: 285 protected:
286 virtual uint64_t GetRevisionInternal(VolumeProjection projection, 286 virtual uint64_t GetRevisionInternal(VolumeProjection projection,
287 unsigned int sliceIndex) const = 0; 287 unsigned int sliceIndex) const = 0;
288 288
289 virtual const DicomInstanceParameters& GetDicomParameters(VolumeProjection projection,
290 unsigned int sliceIndex) const = 0;
291
292 public: 289 public:
293 DicomVolumeImageOrthogonalSlice(const ImageBuffer3D& image, 290 DicomVolumeImageOrthogonalSlice(const IVolumeImage& volume,
294 const VolumeImageGeometry& geometry,
295 const CoordinateSystem3D& cuttingPlane) : 291 const CoordinateSystem3D& cuttingPlane) :
296 image_(image), 292 volume_(volume)
297 geometry_(geometry) 293 {
298 { 294 valid_ = (volume_.HasDicomParameters() &&
299 valid_ = geometry_.DetectSlice(projection_, sliceIndex_, cuttingPlane); 295 volume_.GetGeometry().DetectSlice(projection_, sliceIndex_, cuttingPlane));
300 } 296 }
301 297
302 VolumeProjection GetProjection() const 298 VolumeProjection GetProjection() const
303 { 299 {
304 CheckValid(); 300 CheckValid();
334 } 330 }
335 331
336 std::auto_ptr<TextureBaseSceneLayer> texture; 332 std::auto_ptr<TextureBaseSceneLayer> texture;
337 333
338 { 334 {
339 const DicomInstanceParameters& parameters = GetDicomParameters(projection_, sliceIndex_); 335 const DicomInstanceParameters& parameters = volume_.GetDicomParameters();
340 ImageBuffer3D::SliceReader reader(image_, projection_, sliceIndex_); 336 ImageBuffer3D::SliceReader reader(volume_.GetPixelData(), projection_, sliceIndex_);
341 texture.reset(dynamic_cast<TextureBaseSceneLayer*> 337 texture.reset(dynamic_cast<TextureBaseSceneLayer*>
342 (configurator->CreateFromDicomImage(reader.GetAccessor(), parameters))); 338 (configurator->CreateTextureFromDicom(reader.GetAccessor(), parameters)));
343 } 339 }
344 340
345 const CoordinateSystem3D& system = geometry_.GetProjectionGeometry(projection_); 341 const CoordinateSystem3D& system = volume_.GetGeometry().GetProjectionGeometry(projection_);
346 342
347 double x0, y0, x1, y1; 343 double x0, y0, x1, y1;
348 cuttingPlane.ProjectPoint(x0, y0, system.GetOrigin()); 344 cuttingPlane.ProjectPoint(x0, y0, system.GetOrigin());
349 cuttingPlane.ProjectPoint(x1, y1, system.GetOrigin() + system.GetAxisX()); 345 cuttingPlane.ProjectPoint(x1, y1, system.GetOrigin() + system.GetAxisX());
350 texture->SetOrigin(x0, y0); 346 texture->SetOrigin(x0, y0);
355 !LinearAlgebra::IsCloseToZero(dy)) 351 !LinearAlgebra::IsCloseToZero(dy))
356 { 352 {
357 texture->SetAngle(atan2(dy, dx)); 353 texture->SetAngle(atan2(dy, dx));
358 } 354 }
359 355
360 Vector tmp = geometry_.GetVoxelDimensions(projection_); 356 Vector tmp = volume_.GetGeometry().GetVoxelDimensions(projection_);
361 texture->SetPixelSpacing(tmp[0], tmp[1]); 357 texture->SetPixelSpacing(tmp[0], tmp[1]);
362 358
363 return texture.release(); 359 return texture.release();
364 360
365 #if 0 361 #if 0
388 384
389 385
390 class VolumeImageBase : public IVolumeImage 386 class VolumeImageBase : public IVolumeImage
391 { 387 {
392 private: 388 private:
393 uint64_t revision_; 389 uint64_t revision_;
394 std::auto_ptr<VolumeImageGeometry> geometry_; 390 std::auto_ptr<VolumeImageGeometry> geometry_;
395 std::auto_ptr<ImageBuffer3D> image_; 391 std::auto_ptr<ImageBuffer3D> image_;
392 std::auto_ptr<DicomInstanceParameters> parameters_;
396 393
397 protected: 394 protected:
398 void Finalize() 395 void Finalize()
399 { 396 {
400 geometry_.reset(); 397 geometry_.reset();
415 image_.reset(new ImageBuffer3D(format, geometry_->GetWidth(), geometry_->GetHeight(), 412 image_.reset(new ImageBuffer3D(format, geometry_->GetWidth(), geometry_->GetHeight(),
416 geometry_->GetDepth(), false /* don't compute range */)); 413 geometry_->GetDepth(), false /* don't compute range */));
417 414
418 revision_ ++; 415 revision_ ++;
419 } 416 }
417
418 void SetDicomParameters(const DicomInstanceParameters& parameters)
419 {
420 parameters_.reset(parameters.Clone());
421 revision_ ++;
422 }
420 423
421 ImageBuffer3D& GetPixelData() 424 ImageBuffer3D& GetPixelData()
422 { 425 {
423 return *image_; 426 return *image_;
424 } 427 }
466 else 469 else
467 { 470 {
468 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); 471 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
469 } 472 }
470 } 473 }
474
475 virtual bool HasDicomParameters() const
476 {
477 return parameters_.get() != NULL;
478 }
479
480 virtual const DicomInstanceParameters& GetDicomParameters() const
481 {
482 if (HasDicomParameters())
483 {
484 return *parameters_;
485 }
486 else
487 {
488 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
489 }
490 }
471 }; 491 };
472 492
473 493
474 494
475 495
497 // revision of the volume 517 // revision of the volume
498 return that_.GetRevision(); 518 return that_.GetRevision();
499 } 519 }
500 } 520 }
501 521
502 virtual const DicomInstanceParameters& GetDicomParameters(VolumeProjection projection,
503 unsigned int sliceIndex) const
504 {
505 return that_.GetSliceParameters(projection == VolumeProjection_Axial ? sliceIndex : 0);
506 }
507
508 public: 522 public:
509 ExtractedOrthogonalSlice(const DicomSeriesVolumeImage& that, 523 ExtractedOrthogonalSlice(const DicomSeriesVolumeImage& that,
510 const CoordinateSystem3D& plane) : 524 const CoordinateSystem3D& plane) :
511 DicomVolumeImageOrthogonalSlice(that.GetPixelData(), that.GetGeometry(), plane), 525 DicomVolumeImageOrthogonalSlice(that, plane),
512 that_(that) 526 that_(that)
513 { 527 {
514 } 528 }
515 }; 529 };
516 530
660 geometry->SetAxialGeometry(slices.GetSliceGeometry(0)); 674 geometry->SetAxialGeometry(slices.GetSliceGeometry(0));
661 geometry->SetVoxelDimensions(parameters.GetPixelSpacingX(), 675 geometry->SetVoxelDimensions(parameters.GetPixelSpacingX(),
662 parameters.GetPixelSpacingY(), spacingZ); 676 parameters.GetPixelSpacingY(), spacingZ);
663 677
664 VolumeImageBase::Initialize(geometry.release(), parameters.GetExpectedPixelFormat()); 678 VolumeImageBase::Initialize(geometry.release(), parameters.GetExpectedPixelFormat());
679 VolumeImageBase::SetDicomParameters(parameters);
665 } 680 }
666 681
667 GetPixelData().Clear(); 682 GetPixelData().Clear();
668 } 683 }
669 684
808 } 823 }
809 824
810 if (volume_.GetSlicesCount() != 0) 825 if (volume_.GetSlicesCount() != 0)
811 { 826 {
812 strategy_.reset(new BasicFetchingStrategy(sorter_->CreateSorter( 827 strategy_.reset(new BasicFetchingStrategy(sorter_->CreateSorter(
813 static_cast<unsigned int>(volume_.GetSlicesCount())), BEST_QUALITY)); 828 static_cast<unsigned int>(volume_.GetSlicesCount())), BEST_QUALITY));
814 829
815 assert(simultaneousDownloads_ != 0); 830 assert(simultaneousDownloads_ != 0);
816 for (unsigned int i = 0; i < simultaneousDownloads_; i++) 831 for (unsigned int i = 0; i < simultaneousDownloads_; i++)
817 { 832 {
818 ScheduleNextSliceDownload(); 833 ScheduleNextSliceDownload();
924 oracle_.Schedule(*this, command.release()); 939 oracle_.Schedule(*this, command.release());
925 } 940 }
926 } 941 }
927 942
928 943
929 virtual bool HasVolumeImage() const 944 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane)
930 {
931 return true;
932 }
933
934
935 virtual const IVolumeImage& GetVolumeImage() const
936 {
937 return volume_;
938 }
939
940
941 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const
942 { 945 {
943 if (volume_.HasGeometry() && 946 if (volume_.HasGeometry() &&
944 volume_.GetSlicesCount() != 0) 947 volume_.GetSlicesCount() != 0)
945 { 948 {
946 std::auto_ptr<DicomVolumeImageOrthogonalSlice> slice 949 std::auto_ptr<DicomVolumeImageOrthogonalSlice> slice
957 960
958 return slice.release(); 961 return slice.release();
959 } 962 }
960 else 963 else
961 { 964 {
962 return new InvalidExtractedSlice; 965 return new IVolumeSlicer::InvalidSlice;
963 } 966 }
964 } 967 }
965 }; 968 };
966 969
967 970
1123 IOracle& oracle_; 1126 IOracle& oracle_;
1124 bool active_; 1127 bool active_;
1125 std::string instanceId_; 1128 std::string instanceId_;
1126 std::string transferSyntaxUid_; 1129 std::string transferSyntaxUid_;
1127 1130
1128 std::auto_ptr<DicomInstanceParameters> dicom_;
1129
1130 1131
1131 const std::string& GetInstanceId() const 1132 const std::string& GetInstanceId() const
1132 { 1133 {
1133 if (active_) 1134 if (active_)
1134 { 1135 {
1176 } 1177 }
1177 1178
1178 1179
1179 void SetGeometry(const Orthanc::DicomMap& dicom) 1180 void SetGeometry(const Orthanc::DicomMap& dicom)
1180 { 1181 {
1181 dicom_.reset(new DicomInstanceParameters(dicom)); 1182 DicomInstanceParameters parameters(dicom);
1182 1183 VolumeImageBase::SetDicomParameters(parameters);
1184
1183 Orthanc::PixelFormat format; 1185 Orthanc::PixelFormat format;
1184 if (!dicom_->GetImageInformation().ExtractPixelFormat(format, true)) 1186 if (!parameters.GetImageInformation().ExtractPixelFormat(format, true))
1185 { 1187 {
1186 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 1188 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1187 } 1189 }
1188 1190
1189 double spacingZ; 1191 double spacingZ;
1190 switch (dicom_->GetSopClassUid()) 1192 switch (parameters.GetSopClassUid())
1191 { 1193 {
1192 case SopClassUid_RTDose: 1194 case SopClassUid_RTDose:
1193 spacingZ = dicom_->GetThickness(); 1195 spacingZ = parameters.GetThickness();
1194 break; 1196 break;
1195 1197
1196 default: 1198 default:
1197 throw Orthanc::OrthancException( 1199 throw Orthanc::OrthancException(
1198 Orthanc::ErrorCode_NotImplemented, 1200 Orthanc::ErrorCode_NotImplemented,
1199 "No support for multiframe instances with SOP class UID: " + GetSopClassUid(dicom)); 1201 "No support for multiframe instances with SOP class UID: " + GetSopClassUid(dicom));
1200 } 1202 }
1201 1203
1202 const unsigned int width = dicom_->GetImageInformation().GetWidth(); 1204 const unsigned int width = parameters.GetImageInformation().GetWidth();
1203 const unsigned int height = dicom_->GetImageInformation().GetHeight(); 1205 const unsigned int height = parameters.GetImageInformation().GetHeight();
1204 const unsigned int depth = dicom_->GetImageInformation().GetNumberOfFrames(); 1206 const unsigned int depth = parameters.GetImageInformation().GetNumberOfFrames();
1205 1207
1206 { 1208 {
1207 std::auto_ptr<VolumeImageGeometry> geometry(new VolumeImageGeometry); 1209 std::auto_ptr<VolumeImageGeometry> geometry(new VolumeImageGeometry);
1208 geometry->SetSize(width, height, depth); 1210 geometry->SetSize(width, height, depth);
1209 geometry->SetAxialGeometry(dicom_->GetGeometry()); 1211 geometry->SetAxialGeometry(parameters.GetGeometry());
1210 geometry->SetVoxelDimensions(dicom_->GetPixelSpacingX(), 1212 geometry->SetVoxelDimensions(parameters.GetPixelSpacingX(),
1211 dicom_->GetPixelSpacingY(), 1213 parameters.GetPixelSpacingY(),
1212 spacingZ); 1214 spacingZ);
1213 VolumeImageBase::Initialize(geometry.release(), format); 1215 VolumeImageBase::Initialize(geometry.release(), format);
1214 } 1216 }
1215 1217
1216 GetPixelData().Clear(); 1218 GetPixelData().Clear();
1306 unsigned int sliceIndex) const 1308 unsigned int sliceIndex) const
1307 { 1309 {
1308 return that_.GetRevision(); 1310 return that_.GetRevision();
1309 } 1311 }
1310 1312
1311 virtual const DicomInstanceParameters& GetDicomParameters(VolumeProjection projection,
1312 unsigned int sliceIndex) const
1313 {
1314 return that_.GetDicomParameters();
1315 }
1316
1317 public: 1313 public:
1318 ExtractedOrthogonalSlice(const OrthancMultiframeVolumeLoader& that, 1314 ExtractedOrthogonalSlice(const OrthancMultiframeVolumeLoader& that,
1319 const CoordinateSystem3D& plane) : 1315 const CoordinateSystem3D& plane) :
1320 DicomVolumeImageOrthogonalSlice(that.GetPixelData(), that.GetGeometry(), plane), 1316 DicomVolumeImageOrthogonalSlice(that, plane),
1321 that_(that) 1317 that_(that)
1322 { 1318 {
1323 } 1319 }
1324 }; 1320 };
1325 1321
1336 new Callable<OrthancMultiframeVolumeLoader, OrthancRestApiCommand::SuccessMessage> 1332 new Callable<OrthancMultiframeVolumeLoader, OrthancRestApiCommand::SuccessMessage>
1337 (*this, &OrthancMultiframeVolumeLoader::Handle)); 1333 (*this, &OrthancMultiframeVolumeLoader::Handle));
1338 } 1334 }
1339 1335
1340 1336
1341 virtual bool HasVolumeImage() const
1342 {
1343 return true;
1344 }
1345
1346
1347 virtual const IVolumeImage& GetVolumeImage() const
1348 {
1349 return *this;
1350 }
1351
1352
1353 const DicomInstanceParameters& GetDicomParameters() const
1354 {
1355 if (!HasGeometry())
1356 {
1357 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
1358 }
1359 else
1360 {
1361 return *dicom_;
1362 }
1363 }
1364
1365
1366 void LoadInstance(const std::string& instanceId) 1337 void LoadInstance(const std::string& instanceId)
1367 { 1338 {
1368 if (active_) 1339 if (active_)
1369 { 1340 {
1370 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); 1341 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
1390 } 1361 }
1391 } 1362 }
1392 } 1363 }
1393 1364
1394 1365
1395 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const 1366 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane)
1396 { 1367 {
1397 if (HasGeometry()) 1368 if (HasGeometry())
1398 { 1369 {
1399 return new ExtractedOrthogonalSlice(*this, cuttingPlane); 1370 return new ExtractedOrthogonalSlice(*this, cuttingPlane);
1400 } 1371 }
1401 else 1372 else
1402 { 1373 {
1403 return new InvalidExtractedSlice; 1374 return new IVolumeSlicer::InvalidSlice;
1404 } 1375 }
1405 } 1376 }
1406 }; 1377 };
1407 1378
1408 1379
1409 1380
1410 class DicomSeriesVolumeImageReslicer : public IVolumeSlicer 1381 class VolumeImageReslicer : public IVolumeSlicer
1411 { 1382 {
1412 private: 1383 private:
1413 class Slice : public IExtractedSlice 1384 class Slice : public IExtractedSlice
1414 { 1385 {
1386 private:
1387 VolumeImageReslicer& that_;
1388 CoordinateSystem3D cuttingPlane_;
1389
1415 public: 1390 public:
1391 Slice(VolumeImageReslicer& that,
1392 const CoordinateSystem3D& cuttingPlane) :
1393 that_(that),
1394 cuttingPlane_(cuttingPlane)
1395 {
1396 }
1397
1416 virtual bool IsValid() 1398 virtual bool IsValid()
1417 { 1399 {
1400 return true;
1418 } 1401 }
1419 1402
1420 virtual uint64_t GetRevision() 1403 virtual uint64_t GetRevision()
1421 { 1404 {
1405 return that_.volume_->GetRevision();
1422 } 1406 }
1423 1407
1424 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator, // possibly absent 1408 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator, // possibly absent
1425 const CoordinateSystem3D& cuttingPlane) 1409 const CoordinateSystem3D& cuttingPlane)
1426 { 1410 {
1411 if (configurator == NULL)
1412 {
1413 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
1414 "Must provide a layer style configurator");
1415 }
1416
1417 that_.reslicer_.SetOutputFormat(that_.volume_->GetPixelData().GetFormat());
1418
1419 if (that_.reslicer_.IsSuccess())
1420 {
1421 std::auto_ptr<TextureBaseSceneLayer> layer
1422 (configurator->CreateTextureFromDicom(that_.reslicer_.GetOutputSlice(),
1423 that_.volume_->GetDicomParameters()));
1424 if (layer.get() == NULL)
1425 {
1426 return NULL;
1427 }
1428
1429 return layer.release();
1430 }
1431 else
1432 {
1433 return NULL;
1434 }
1427 } 1435 }
1428 }; 1436 };
1429 1437
1430 VolumeReslicer reslicer_; 1438 boost::shared_ptr<IVolumeImage> volume_;
1431 boost::shared_ptr<DicomSeriesVolumeImage> image_; 1439 VolumeReslicer reslicer_;
1432 1440
1433 public: 1441 public:
1434 DicomSeriesVolumeImageReslicer(const boost::shared_ptr<DicomSeriesVolumeImage>& image) : 1442 VolumeImageReslicer(const boost::shared_ptr<IVolumeImage>& volume) :
1435 image_(image) 1443 volume_(volume)
1436 { 1444 {
1437 } 1445 if (volume.get() == NULL)
1438 1446 {
1439 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const 1447 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
1440 { 1448 }
1449 }
1450
1451 ImageInterpolation GetInterpolation() const
1452 {
1453 return reslicer_.GetInterpolation();
1454 }
1455
1456 void SetInterpolation(ImageInterpolation interpolation)
1457 {
1458 reslicer_.SetInterpolation(interpolation);
1459 }
1460
1461 bool IsFastMode() const
1462 {
1463 return reslicer_.IsFastMode();
1464 }
1465
1466 void SetFastMode(bool fast)
1467 {
1468 reslicer_.EnableFastMode(fast);
1469 }
1470
1471 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane)
1472 {
1473 if (volume_->HasGeometry())
1474 {
1475 return new Slice(*this, cuttingPlane);
1476 }
1477 else
1478 {
1479 return new IVolumeSlicer::InvalidSlice;
1480 }
1441 } 1481 }
1442 }; 1482 };
1443 1483
1444 1484
1445 1485
1608 NativeApplicationContext& that_; 1648 NativeApplicationContext& that_;
1609 boost::shared_lock<boost::shared_mutex> lock_; 1649 boost::shared_lock<boost::shared_mutex> lock_;
1610 1650
1611 public: 1651 public:
1612 ReaderLock(NativeApplicationContext& that) : 1652 ReaderLock(NativeApplicationContext& that) :
1613 that_(that), 1653 that_(that),
1614 lock_(that.mutex_) 1654 lock_(that.mutex_)
1615 { 1655 {
1616 } 1656 }
1617 }; 1657 };
1618 1658
1619 1659
1623 NativeApplicationContext& that_; 1663 NativeApplicationContext& that_;
1624 boost::unique_lock<boost::shared_mutex> lock_; 1664 boost::unique_lock<boost::shared_mutex> lock_;
1625 1665
1626 public: 1666 public:
1627 WriterLock(NativeApplicationContext& that) : 1667 WriterLock(NativeApplicationContext& that) :
1628 that_(that), 1668 that_(that),
1629 lock_(that.mutex_) 1669 lock_(that.mutex_)
1630 { 1670 {
1631 } 1671 }
1632 1672
1633 MessageBroker& GetBroker() 1673 MessageBroker& GetBroker()
1634 { 1674 {
1690 1730
1691 void Handle(const OrthancStone::IVolumeImage::GeometryReadyMessage& message) 1731 void Handle(const OrthancStone::IVolumeImage::GeometryReadyMessage& message)
1692 { 1732 {
1693 printf("Geometry ready\n"); 1733 printf("Geometry ready\n");
1694 1734
1695 if (source2_->GetSlicer().HasVolumeImage() && 1735 //plane_ = message.GetOrigin().GetGeometry().GetSagittalGeometry();
1696 &source2_->GetSlicer().GetVolumeImage() == &message.GetOrigin()) 1736 //plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry();
1697 { 1737 plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry();
1698 //plane_ = message.GetOrigin().GetGeometry().GetSagittalGeometry(); 1738 plane_.SetOrigin(message.GetOrigin().GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f));
1699 //plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry();
1700 plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry();
1701 plane_.SetOrigin(message.GetOrigin().GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f));
1702 }
1703 1739
1704 Refresh(); 1740 Refresh();
1705 } 1741 }
1706 1742
1707 1743
1807 1843
1808 void SetVolume2(int depth, 1844 void SetVolume2(int depth,
1809 const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume, 1845 const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume,
1810 OrthancStone::ILayerStyleConfigurator* style) 1846 OrthancStone::ILayerStyleConfigurator* style)
1811 { 1847 {
1812 dynamic_cast<OrthancStone::IObservable&>(*volume).RegisterObserverCallback
1813 (new OrthancStone::Callable
1814 <Toto, OrthancStone::IVolumeImage::GeometryReadyMessage>(*this, &Toto::Handle));
1815
1816 source2_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume)); 1848 source2_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume));
1817 1849
1818 if (style != NULL) 1850 if (style != NULL)
1819 { 1851 {
1820 source2_->SetConfigurator(style); 1852 source2_->SetConfigurator(style);
1836 loader1.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable())); 1868 loader1.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable()));
1837 loader2.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable())); 1869 loader2.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable()));
1838 loader3.reset(new OrthancStone::OrthancMultiframeVolumeLoader(oracle, lock.GetOracleObservable())); 1870 loader3.reset(new OrthancStone::OrthancMultiframeVolumeLoader(oracle, lock.GetOracleObservable()));
1839 } 1871 }
1840 1872
1873
1874 #if 1
1841 toto->SetVolume1(0, loader1, new OrthancStone::GrayscaleStyleConfigurator); 1875 toto->SetVolume1(0, loader1, new OrthancStone::GrayscaleStyleConfigurator);
1876 #else
1877 {
1878 boost::shared_ptr<OrthancStone::IVolumeSlicer> reslicer(new OrthancStone::VolumeImageReslicer(loader1));
1879 toto->SetVolume1(0, reslicer, new OrthancStone::GrayscaleStyleConfigurator);
1880 }
1881 #endif
1882
1842 1883
1843 { 1884 {
1844 std::auto_ptr<OrthancStone::LookupTableStyleConfigurator> config(new OrthancStone::LookupTableStyleConfigurator); 1885 std::auto_ptr<OrthancStone::LookupTableStyleConfigurator> config(new OrthancStone::LookupTableStyleConfigurator);
1845 config->SetLookupTable(Orthanc::EmbeddedResources::COLORMAP_HOT); 1886 config->SetLookupTable(Orthanc::EmbeddedResources::COLORMAP_HOT);
1846 toto->SetVolume2(1, loader3, config.release()); 1887 toto->SetVolume2(1, loader3, config.release());