Mercurial > hg > orthanc-stone
comparison Framework/dev.h @ 551:90f3a60576a9 dev rtviewer19
Merged in ct-pet-dose-struct (pull request #2)
Ct pet dose struct
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Tue, 02 Apr 2019 14:02:12 +0000 |
parents | 1d9deb4ee84c |
children | 573e35378999 |
comparison
equal
deleted
inserted
replaced
545:e1ba16436d59 | 551:90f3a60576a9 |
---|---|
49 OrthancSlicesLoader loader_; | 49 OrthancSlicesLoader loader_; |
50 std::auto_ptr<ImageBuffer3D> image_; | 50 std::auto_ptr<ImageBuffer3D> image_; |
51 std::auto_ptr<DownloadStack> downloadStack_; | 51 std::auto_ptr<DownloadStack> downloadStack_; |
52 bool computeRange_; | 52 bool computeRange_; |
53 size_t pendingSlices_; | 53 size_t pendingSlices_; |
54 | 54 |
55 void ScheduleSliceDownload() | 55 void ScheduleSliceDownload() |
56 { | 56 { |
57 assert(downloadStack_.get() != NULL); | 57 assert(downloadStack_.get() != NULL); |
58 | 58 |
59 unsigned int slice; | 59 unsigned int slice; |
68 const Slice& b) | 68 const Slice& b) |
69 { | 69 { |
70 if (!GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(), | 70 if (!GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(), |
71 b.GetGeometry().GetNormal())) | 71 b.GetGeometry().GetNormal())) |
72 { | 72 { |
73 LOG(ERROR) << "Some slice in the volume image is not parallel to the others"; | 73 LOG(ERROR) << "A slice in the volume image is not parallel to the others."; |
74 return false; | 74 return false; |
75 } | 75 } |
76 | 76 |
77 if (a.GetConverter().GetExpectedPixelFormat() != b.GetConverter().GetExpectedPixelFormat()) | 77 if (a.GetConverter().GetExpectedPixelFormat() != b.GetConverter().GetExpectedPixelFormat()) |
78 { | 78 { |
79 LOG(ERROR) << "The pixel format changes across the slices of the volume image"; | 79 LOG(ERROR) << "The pixel format changes across the slices of the volume image."; |
80 return false; | 80 return false; |
81 } | 81 } |
82 | 82 |
83 if (a.GetWidth() != b.GetWidth() || | 83 if (a.GetWidth() != b.GetWidth() || |
84 a.GetHeight() != b.GetHeight()) | 84 a.GetHeight() != b.GetHeight()) |
85 { | 85 { |
86 LOG(ERROR) << "The width/height of the slices change across the volume image"; | 86 LOG(ERROR) << "The slices dimensions (width/height) are varying throughout the volume image"; |
87 return false; | 87 return false; |
88 } | 88 } |
89 | 89 |
90 if (!LinearAlgebra::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) || | 90 if (!LinearAlgebra::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) || |
91 !LinearAlgebra::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY())) | 91 !LinearAlgebra::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY())) |
107 | 107 |
108 | 108 |
109 void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message) | 109 void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message) |
110 { | 110 { |
111 assert(&message.GetOrigin() == &loader_); | 111 assert(&message.GetOrigin() == &loader_); |
112 | 112 |
113 if (loader_.GetSliceCount() == 0) | 113 if (loader_.GetSliceCount() == 0) |
114 { | 114 { |
115 LOG(ERROR) << "Empty volume image"; | 115 LOG(ERROR) << "Empty volume image"; |
116 EmitMessage(ISlicedVolume::GeometryErrorMessage(*this)); | 116 EmitMessage(ISlicedVolume::GeometryErrorMessage(*this)); |
117 return; | 117 return; |
154 unsigned int height = loader_.GetSlice(0).GetHeight(); | 154 unsigned int height = loader_.GetSlice(0).GetHeight(); |
155 Orthanc::PixelFormat format = loader_.GetSlice(0).GetConverter().GetExpectedPixelFormat(); | 155 Orthanc::PixelFormat format = loader_.GetSlice(0).GetConverter().GetExpectedPixelFormat(); |
156 LOG(INFO) << "Creating a volume image of size " << width << "x" << height | 156 LOG(INFO) << "Creating a volume image of size " << width << "x" << height |
157 << "x" << loader_.GetSliceCount() << " in " << Orthanc::EnumerationToString(format); | 157 << "x" << loader_.GetSliceCount() << " in " << Orthanc::EnumerationToString(format); |
158 | 158 |
159 image_.reset(new ImageBuffer3D(format, width, height, loader_.GetSliceCount(), computeRange_)); | 159 image_.reset(new ImageBuffer3D(format, width, height, static_cast<unsigned int>(loader_.GetSliceCount()), computeRange_)); |
160 image_->SetAxialGeometry(loader_.GetSlice(0).GetGeometry()); | 160 image_->SetAxialGeometry(loader_.GetSlice(0).GetGeometry()); |
161 image_->SetVoxelDimensions(loader_.GetSlice(0).GetPixelSpacingX(), | 161 image_->SetVoxelDimensions(loader_.GetSlice(0).GetPixelSpacingX(), |
162 loader_.GetSlice(0).GetPixelSpacingY(), spacingZ); | 162 loader_.GetSlice(0).GetPixelSpacingY(), spacingZ); |
163 image_->Clear(); | 163 image_->Clear(); |
164 | 164 |
165 downloadStack_.reset(new DownloadStack(loader_.GetSliceCount())); | 165 downloadStack_.reset(new DownloadStack(static_cast<unsigned int>(loader_.GetSliceCount()))); |
166 pendingSlices_ = loader_.GetSliceCount(); | 166 pendingSlices_ = loader_.GetSliceCount(); |
167 | 167 |
168 for (unsigned int i = 0; i < 4; i++) // Limit to 4 simultaneous downloads | 168 for (unsigned int i = 0; i < 4; i++) // Limit to 4 simultaneous downloads |
169 { | 169 { |
170 ScheduleSliceDownload(); | 170 ScheduleSliceDownload(); |
173 // TODO Check the DicomFrameConverter are constant | 173 // TODO Check the DicomFrameConverter are constant |
174 | 174 |
175 EmitMessage(ISlicedVolume::GeometryReadyMessage(*this)); | 175 EmitMessage(ISlicedVolume::GeometryReadyMessage(*this)); |
176 } | 176 } |
177 | 177 |
178 | 178 |
179 void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message) | 179 void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message) |
180 { | 180 { |
181 assert(&message.GetOrigin() == &loader_); | 181 assert(&message.GetOrigin() == &loader_); |
182 | 182 |
183 LOG(ERROR) << "Unable to download a volume image"; | 183 LOG(ERROR) << "Unable to download a volume image"; |
184 EmitMessage(ISlicedVolume::GeometryErrorMessage(*this)); | 184 EmitMessage(ISlicedVolume::GeometryErrorMessage(*this)); |
185 } | 185 } |
186 | 186 |
187 | 187 |
188 void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message) | 188 void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message) |
189 { | 189 { |
190 assert(&message.GetOrigin() == &loader_); | 190 assert(&message.GetOrigin() == &loader_); |
191 | 191 |
192 { | 192 { |
208 } | 208 } |
209 | 209 |
210 ScheduleSliceDownload(); | 210 ScheduleSliceDownload(); |
211 } | 211 } |
212 | 212 |
213 | 213 |
214 void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message) | 214 void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message) |
215 { | 215 { |
216 assert(&message.GetOrigin() == &loader_); | 216 assert(&message.GetOrigin() == &loader_); |
217 | 217 |
218 LOG(ERROR) << "Cannot download slice " << message.GetSliceIndex() << " in a volume image"; | 218 LOG(ERROR) << "Cannot download slice " << message.GetSliceIndex() << " in a volume image"; |
310 double pixelSpacingX_; | 310 double pixelSpacingX_; |
311 double pixelSpacingY_; | 311 double pixelSpacingY_; |
312 double sliceThickness_; | 312 double sliceThickness_; |
313 CoordinateSystem3D reference_; | 313 CoordinateSystem3D reference_; |
314 DicomFrameConverter converter_; | 314 DicomFrameConverter converter_; |
315 | 315 |
316 double ComputeAxialThickness(const OrthancVolumeImage& volume) const | 316 double ComputeAxialThickness(const OrthancVolumeImage& volume) const |
317 { | 317 { |
318 double thickness; | 318 double thickness; |
319 | 319 |
320 size_t n = volume.GetSliceCount(); | 320 size_t n = volume.GetSliceCount(); |
321 if (n > 1) | 321 if (n > 1) |
322 { | 322 { |
323 const Slice& a = volume.GetSlice(0); | 323 const Slice& a = volume.GetSlice(0); |
324 const Slice& b = volume.GetSlice(n - 1); | 324 const Slice& b = volume.GetSlice(n - 1); |
340 else | 340 else |
341 { | 341 { |
342 return thickness; | 342 return thickness; |
343 } | 343 } |
344 } | 344 } |
345 | 345 |
346 void SetupAxial(const OrthancVolumeImage& volume) | 346 void SetupAxial(const OrthancVolumeImage& volume) |
347 { | 347 { |
348 const Slice& axial = volume.GetSlice(0); | 348 const Slice& axial = volume.GetSlice(0); |
349 | 349 |
350 width_ = axial.GetWidth(); | 350 width_ = axial.GetWidth(); |
351 height_ = axial.GetHeight(); | 351 height_ = axial.GetHeight(); |
352 depth_ = volume.GetSliceCount(); | 352 depth_ = volume.GetSliceCount(); |
353 | 353 |
354 pixelSpacingX_ = axial.GetPixelSpacingX(); | 354 pixelSpacingX_ = axial.GetPixelSpacingX(); |
362 { | 362 { |
363 const Slice& axial = volume.GetSlice(0); | 363 const Slice& axial = volume.GetSlice(0); |
364 double axialThickness = ComputeAxialThickness(volume); | 364 double axialThickness = ComputeAxialThickness(volume); |
365 | 365 |
366 width_ = axial.GetWidth(); | 366 width_ = axial.GetWidth(); |
367 height_ = volume.GetSliceCount(); | 367 height_ = static_cast<unsigned int>(volume.GetSliceCount()); |
368 depth_ = axial.GetHeight(); | 368 depth_ = axial.GetHeight(); |
369 | 369 |
370 pixelSpacingX_ = axial.GetPixelSpacingX(); | 370 pixelSpacingX_ = axial.GetPixelSpacingX(); |
371 pixelSpacingY_ = axialThickness; | 371 pixelSpacingY_ = axialThickness; |
372 sliceThickness_ = axial.GetPixelSpacingY(); | 372 sliceThickness_ = axial.GetPixelSpacingY(); |
373 | 373 |
374 Vector origin = axial.GetGeometry().GetOrigin(); | 374 Vector origin = axial.GetGeometry().GetOrigin(); |
375 origin += (static_cast<double>(volume.GetSliceCount() - 1) * | 375 origin += (static_cast<double>(volume.GetSliceCount() - 1) * |
376 axialThickness * axial.GetGeometry().GetNormal()); | 376 axialThickness * axial.GetGeometry().GetNormal()); |
377 | 377 |
378 reference_ = CoordinateSystem3D(origin, | 378 reference_ = CoordinateSystem3D(origin, |
379 axial.GetGeometry().GetAxisX(), | 379 axial.GetGeometry().GetAxisX(), |
380 -axial.GetGeometry().GetNormal()); | 380 - axial.GetGeometry().GetNormal()); |
381 } | 381 } |
382 | 382 |
383 void SetupSagittal(const OrthancVolumeImage& volume) | 383 void SetupSagittal(const OrthancVolumeImage& volume) |
384 { | 384 { |
385 const Slice& axial = volume.GetSlice(0); | 385 const Slice& axial = volume.GetSlice(0); |
386 double axialThickness = ComputeAxialThickness(volume); | 386 double axialThickness = ComputeAxialThickness(volume); |
387 | 387 |
388 width_ = axial.GetHeight(); | 388 width_ = axial.GetHeight(); |
389 height_ = volume.GetSliceCount(); | 389 height_ = static_cast<unsigned int>(volume.GetSliceCount()); |
390 depth_ = axial.GetWidth(); | 390 depth_ = axial.GetWidth(); |
391 | 391 |
392 pixelSpacingX_ = axial.GetPixelSpacingY(); | 392 pixelSpacingX_ = axial.GetPixelSpacingY(); |
393 pixelSpacingY_ = axialThickness; | 393 pixelSpacingY_ = axialThickness; |
394 sliceThickness_ = axial.GetPixelSpacingX(); | 394 sliceThickness_ = axial.GetPixelSpacingX(); |
395 | 395 |
396 Vector origin = axial.GetGeometry().GetOrigin(); | 396 Vector origin = axial.GetGeometry().GetOrigin(); |
397 origin += (static_cast<double>(volume.GetSliceCount() - 1) * | 397 origin += (static_cast<double>(volume.GetSliceCount() - 1) * |
398 axialThickness * axial.GetGeometry().GetNormal()); | 398 axialThickness * axial.GetGeometry().GetNormal()); |
399 | 399 |
400 reference_ = CoordinateSystem3D(origin, | 400 reference_ = CoordinateSystem3D(origin, |
401 axial.GetGeometry().GetAxisY(), | 401 axial.GetGeometry().GetAxisY(), |
402 axial.GetGeometry().GetNormal()); | 402 axial.GetGeometry().GetNormal()); |
403 } | 403 } |
404 | 404 |
413 | 413 |
414 converter_ = volume.GetSlice(0).GetConverter(); | 414 converter_ = volume.GetSlice(0).GetConverter(); |
415 | 415 |
416 switch (projection) | 416 switch (projection) |
417 { | 417 { |
418 case VolumeProjection_Axial: | 418 case VolumeProjection_Axial: |
419 SetupAxial(volume); | 419 SetupAxial(volume); |
420 break; | 420 break; |
421 | 421 |
422 case VolumeProjection_Coronal: | 422 case VolumeProjection_Coronal: |
423 SetupCoronal(volume); | 423 SetupCoronal(volume); |
424 break; | 424 break; |
425 | 425 |
426 case VolumeProjection_Sagittal: | 426 case VolumeProjection_Sagittal: |
427 SetupSagittal(volume); | 427 SetupSagittal(volume); |
428 break; | 428 break; |
429 | 429 |
430 default: | 430 default: |
431 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | 431 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); |
432 } | 432 } |
433 } | 433 } |
434 | 434 |
435 size_t GetSliceCount() const | 435 size_t GetSliceCount() const |
436 { | 436 { |
439 | 439 |
440 const Vector& GetNormal() const | 440 const Vector& GetNormal() const |
441 { | 441 { |
442 return reference_.GetNormal(); | 442 return reference_.GetNormal(); |
443 } | 443 } |
444 | 444 |
445 bool LookupSlice(size_t& index, | 445 bool LookupSlice(size_t& index, |
446 const CoordinateSystem3D& slice) const | 446 const CoordinateSystem3D& slice) const |
447 { | 447 { |
448 bool opposite; | 448 bool opposite; |
449 if (!GeometryToolbox::IsParallelOrOpposite(opposite, | 449 if (!GeometryToolbox::IsParallelOrOpposite(opposite, |
450 reference_.GetNormal(), | 450 reference_.GetNormal(), |
451 slice.GetNormal())) | 451 slice.GetNormal())) |
452 { | 452 { |
453 return false; | 453 return false; |
454 } | 454 } |
455 | 455 |
456 double z = (reference_.ProjectAlongNormal(slice.GetOrigin()) - | 456 double z = (reference_.ProjectAlongNormal(slice.GetOrigin()) - |
457 reference_.ProjectAlongNormal(reference_.GetOrigin())) / sliceThickness_; | 457 reference_.ProjectAlongNormal(reference_.GetOrigin())) / sliceThickness_; |
458 | 458 |
459 int s = static_cast<int>(boost::math::iround(z)); | 459 int s = static_cast<int>(boost::math::iround(z)); |
460 | 460 |
461 if (s < 0 || | 461 if (s < 0 || |
462 s >= static_cast<int>(depth_)) | 462 s >= static_cast<int>(depth_)) |
463 { | 463 { |
464 return false; | 464 return false; |
465 } | 465 } |
466 else | 466 else |
467 { | 467 { |
505 | 505 |
506 public: | 506 public: |
507 RendererFactory(const Orthanc::ImageAccessor& frame, | 507 RendererFactory(const Orthanc::ImageAccessor& frame, |
508 const Slice& slice, | 508 const Slice& slice, |
509 bool isFullQuality) : | 509 bool isFullQuality) : |
510 frame_(frame), | 510 frame_(frame), |
511 slice_(slice), | 511 slice_(slice), |
512 isFullQuality_(isFullQuality) | 512 isFullQuality_(isFullQuality) |
513 { | 513 { |
514 } | 514 } |
515 | 515 |
516 virtual ILayerRenderer* CreateRenderer() const | 516 virtual ILayerRenderer* CreateRenderer() const |
517 { | 517 { |
523 OrthancVolumeImage& volume_; | 523 OrthancVolumeImage& volume_; |
524 std::auto_ptr<VolumeImageGeometry> axialGeometry_; | 524 std::auto_ptr<VolumeImageGeometry> axialGeometry_; |
525 std::auto_ptr<VolumeImageGeometry> coronalGeometry_; | 525 std::auto_ptr<VolumeImageGeometry> coronalGeometry_; |
526 std::auto_ptr<VolumeImageGeometry> sagittalGeometry_; | 526 std::auto_ptr<VolumeImageGeometry> sagittalGeometry_; |
527 | 527 |
528 | 528 |
529 bool IsGeometryReady() const | 529 bool IsGeometryReady() const |
530 { | 530 { |
531 return axialGeometry_.get() != NULL; | 531 return axialGeometry_.get() != NULL; |
532 } | 532 } |
533 | 533 |
534 void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message) | 534 void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message) |
535 { | 535 { |
536 assert(&message.GetOrigin() == &volume_); | 536 assert(&message.GetOrigin() == &volume_); |
537 | 537 |
538 // These 3 values are only used to speed up the IVolumeSlicer | 538 // These 3 values are only used to speed up the IVolumeSlicer |
539 axialGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Axial)); | 539 axialGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Axial)); |
540 coronalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Coronal)); | 540 coronalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Coronal)); |
541 sagittalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Sagittal)); | 541 sagittalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Sagittal)); |
542 | 542 |
543 EmitMessage(IVolumeSlicer::GeometryReadyMessage(*this)); | 543 EmitMessage(IVolumeSlicer::GeometryReadyMessage(*this)); |
544 } | 544 } |
545 | 545 |
546 void OnGeometryError(const ISlicedVolume::GeometryErrorMessage& message) | 546 void OnGeometryError(const ISlicedVolume::GeometryErrorMessage& message) |
547 { | 547 { |
548 assert(&message.GetOrigin() == &volume_); | 548 assert(&message.GetOrigin() == &volume_); |
549 | 549 |
550 EmitMessage(IVolumeSlicer::GeometryErrorMessage(*this)); | 550 EmitMessage(IVolumeSlicer::GeometryErrorMessage(*this)); |
551 } | 551 } |
552 | 552 |
553 void OnContentChanged(const ISlicedVolume::ContentChangedMessage& message) | 553 void OnContentChanged(const ISlicedVolume::ContentChangedMessage& message) |
554 { | 554 { |
555 assert(&message.GetOrigin() == &volume_); | 555 assert(&message.GetOrigin() == &volume_); |
556 | 556 |
557 EmitMessage(IVolumeSlicer::ContentChangedMessage(*this)); | 557 EmitMessage(IVolumeSlicer::ContentChangedMessage(*this)); |
558 } | 558 } |
559 | 559 |
560 void OnSliceContentChanged(const ISlicedVolume::SliceContentChangedMessage& message) | 560 void OnSliceContentChanged(const ISlicedVolume::SliceContentChangedMessage& message) |
561 { | 561 { |
574 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 574 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
575 } | 575 } |
576 | 576 |
577 switch (projection) | 577 switch (projection) |
578 { | 578 { |
579 case VolumeProjection_Axial: | 579 case VolumeProjection_Axial: |
580 return *axialGeometry_; | 580 return *axialGeometry_; |
581 | 581 |
582 case VolumeProjection_Sagittal: | 582 case VolumeProjection_Sagittal: |
583 return *sagittalGeometry_; | 583 return *sagittalGeometry_; |
584 | 584 |
585 case VolumeProjection_Coronal: | 585 case VolumeProjection_Coronal: |
586 return *coronalGeometry_; | 586 return *coronalGeometry_; |
587 | 587 |
588 default: | 588 default: |
589 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 589 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
590 } | 590 } |
591 } | 591 } |
592 | 592 |
593 | 593 |
594 bool DetectProjection(VolumeProjection& projection, | 594 bool DetectProjection(VolumeProjection& projection, |
623 } | 623 } |
624 } | 624 } |
625 | 625 |
626 | 626 |
627 public: | 627 public: |
628 VolumeImageMPRSlicer(MessageBroker& broker, | 628 VolumeImageMPRSlicer(MessageBroker& broker, |
629 OrthancVolumeImage& volume) : | 629 OrthancVolumeImage& volume) : |
630 IVolumeSlicer(broker), | 630 IVolumeSlicer(broker), |
631 IObserver(broker), | 631 IObserver(broker), |
632 volume_(volume) | 632 volume_(volume) |
633 { | 633 { |
634 volume_.RegisterObserverCallback( | 634 volume_.RegisterObserverCallback( |
635 new Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryReadyMessage> | 635 new Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryReadyMessage> |
636 (*this, &VolumeImageMPRSlicer::OnGeometryReady)); | 636 (*this, &VolumeImageMPRSlicer::OnGeometryReady)); |
637 | 637 |
650 | 650 |
651 virtual bool GetExtent(std::vector<Vector>& points, | 651 virtual bool GetExtent(std::vector<Vector>& points, |
652 const CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE | 652 const CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE |
653 { | 653 { |
654 VolumeProjection projection; | 654 VolumeProjection projection; |
655 | 655 |
656 if (!IsGeometryReady() || | 656 if (!IsGeometryReady() || |
657 !DetectProjection(projection, viewportSlice)) | 657 !DetectProjection(projection, viewportSlice)) |
658 { | 658 { |
659 return false; | 659 return false; |
660 } | 660 } |
662 { | 662 { |
663 // As the slices of the volumic image are arranged in a box, | 663 // As the slices of the volumic image are arranged in a box, |
664 // we only consider one single reference slice (the one with index 0). | 664 // we only consider one single reference slice (the one with index 0). |
665 std::auto_ptr<Slice> slice(GetProjectionGeometry(projection).GetSlice(0)); | 665 std::auto_ptr<Slice> slice(GetProjectionGeometry(projection).GetSlice(0)); |
666 slice->GetExtent(points); | 666 slice->GetExtent(points); |
667 | 667 |
668 return true; | 668 return true; |
669 } | 669 } |
670 } | 670 } |
671 | |
672 | 671 |
673 virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE | 672 virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE |
674 { | 673 { |
675 VolumeProjection projection; | 674 VolumeProjection projection; |
676 | 675 |
677 if (IsGeometryReady() && | 676 if (IsGeometryReady() && |
678 DetectProjection(projection, viewportSlice)) | 677 DetectProjection(projection, viewportSlice)) |
679 { | 678 { |
680 const VolumeImageGeometry& geometry = GetProjectionGeometry(projection); | 679 const VolumeImageGeometry& geometry = GetProjectionGeometry(projection); |
681 | 680 |
686 bool isFullQuality = true; // TODO | 685 bool isFullQuality = true; // TODO |
687 | 686 |
688 std::auto_ptr<Orthanc::Image> frame; | 687 std::auto_ptr<Orthanc::Image> frame; |
689 | 688 |
690 { | 689 { |
691 ImageBuffer3D::SliceReader reader(volume_.GetImage(), projection, closest); | 690 ImageBuffer3D::SliceReader reader(volume_.GetImage(), projection, static_cast<unsigned int>(closest)); |
692 | 691 |
693 // TODO Transfer ownership if non-axial, to avoid memcpy | 692 // TODO Transfer ownership if non-axial, to avoid memcpy |
694 frame.reset(Orthanc::Image::Clone(reader.GetAccessor())); | 693 frame.reset(Orthanc::Image::Clone(reader.GetAccessor())); |
695 } | 694 } |
696 | 695 |
736 } | 735 } |
737 | 736 |
738 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, | 737 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, |
739 const ViewportGeometry& view, | 738 const ViewportGeometry& view, |
740 MouseButton button, | 739 MouseButton button, |
740 KeyboardModifiers modifiers, | |
741 int viewportX, | |
742 int viewportY, | |
741 double x, | 743 double x, |
742 double y, | 744 double y, |
743 IStatusBar* statusBar) | 745 IStatusBar* statusBar, |
744 { | 746 const std::vector<Touch>& touches) ORTHANC_OVERRIDE |
745 return NULL; | 747 { |
748 return NULL; | |
746 } | 749 } |
747 | 750 |
748 virtual void MouseOver(CairoContext& context, | 751 virtual void MouseOver(CairoContext& context, |
749 WorldSceneWidget& widget, | 752 WorldSceneWidget& widget, |
750 const ViewportGeometry& view, | 753 const ViewportGeometry& view, |
751 double x, | 754 double x, |
752 double y, | 755 double y, |
753 IStatusBar* statusBar) | 756 IStatusBar* statusBar) ORTHANC_OVERRIDE |
754 { | 757 { |
755 } | 758 } |
756 | 759 |
757 virtual void MouseWheel(WorldSceneWidget& widget, | 760 virtual void MouseWheel(WorldSceneWidget& widget, |
758 MouseWheelDirection direction, | 761 MouseWheelDirection direction, |
759 KeyboardModifiers modifiers, | 762 KeyboardModifiers modifiers, |
760 IStatusBar* statusBar) | 763 IStatusBar* statusBar) ORTHANC_OVERRIDE |
761 { | 764 { |
762 int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1); | 765 int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1); |
763 | 766 |
764 switch (direction) | 767 switch (direction) |
765 { | 768 { |
766 case MouseWheelDirection_Up: | 769 case MouseWheelDirection_Up: |
767 OffsetSlice(-scale); | 770 OffsetSlice(-scale); |
768 break; | 771 break; |
769 | 772 |
770 case MouseWheelDirection_Down: | 773 case MouseWheelDirection_Down: |
771 OffsetSlice(scale); | 774 OffsetSlice(scale); |
772 break; | 775 break; |
773 | 776 |
774 default: | 777 default: |
775 break; | 778 break; |
776 } | 779 } |
777 } | 780 } |
778 | 781 |
779 virtual void KeyPressed(WorldSceneWidget& widget, | 782 virtual void KeyPressed(WorldSceneWidget& widget, |
780 KeyboardKeys key, | 783 KeyboardKeys key, |
781 char keyChar, | 784 char keyChar, |
782 KeyboardModifiers modifiers, | 785 KeyboardModifiers modifiers, |
783 IStatusBar* statusBar) | 786 IStatusBar* statusBar) ORTHANC_OVERRIDE |
784 { | 787 { |
785 switch (keyChar) | 788 switch (keyChar) |
786 { | 789 { |
787 case 's': | 790 case 's': |
788 widget.FitContent(); | 791 widget.FitContent(); |
789 break; | 792 break; |
790 | 793 |
791 default: | 794 default: |
792 break; | 795 break; |
793 } | 796 } |
794 } | 797 } |
795 | 798 |
796 public: | 799 public: |
797 VolumeImageInteractor(MessageBroker& broker, | 800 VolumeImageInteractor(MessageBroker& broker, |
798 OrthancVolumeImage& volume, | 801 OrthancVolumeImage& volume, |
799 SliceViewerWidget& widget, | 802 SliceViewerWidget& widget, |
800 VolumeProjection projection) : | 803 VolumeProjection projection) : |
801 IObserver(broker), | 804 IObserver(broker), |
802 widget_(widget), | 805 widget_(widget), |
803 projection_(projection) | 806 projection_(projection) |
804 { | 807 { |
805 widget.SetInteractor(*this); | 808 widget.SetInteractor(*this); |
806 | 809 |
807 volume.RegisterObserverCallback( | 810 volume.RegisterObserverCallback( |
808 new Callable<VolumeImageInteractor, ISlicedVolume::GeometryReadyMessage> | 811 new Callable<VolumeImageInteractor, ISlicedVolume::GeometryReadyMessage> |
837 slice = 0; | 840 slice = 0; |
838 } | 841 } |
839 | 842 |
840 if (slice >= static_cast<int>(slices_->GetSliceCount())) | 843 if (slice >= static_cast<int>(slices_->GetSliceCount())) |
841 { | 844 { |
842 slice = slices_->GetSliceCount() - 1; | 845 slice = static_cast<unsigned int>(slices_->GetSliceCount()) - 1; |
843 } | 846 } |
844 | 847 |
845 if (slice != static_cast<int>(slice_)) | 848 if (slice != static_cast<int>(slice_)) |
846 { | 849 { |
847 SetSlice(slice); | 850 SetSlice(slice); |
896 }; | 899 }; |
897 | 900 |
898 SliceViewerWidget& otherPlane_; | 901 SliceViewerWidget& otherPlane_; |
899 | 902 |
900 public: | 903 public: |
901 ReferenceLineSource(MessageBroker& broker, | 904 ReferenceLineSource(MessageBroker& broker, |
902 SliceViewerWidget& otherPlane) : | 905 SliceViewerWidget& otherPlane) : |
903 IVolumeSlicer(broker), | 906 IVolumeSlicer(broker), |
904 otherPlane_(otherPlane) | 907 otherPlane_(otherPlane) |
905 { | 908 { |
906 EmitMessage(IVolumeSlicer::GeometryReadyMessage(*this)); | 909 EmitMessage(IVolumeSlicer::GeometryReadyMessage(*this)); |
913 } | 916 } |
914 | 917 |
915 virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice) | 918 virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice) |
916 { | 919 { |
917 Slice reference(viewportSlice, 0.001); | 920 Slice reference(viewportSlice, 0.001); |
918 | 921 |
919 Vector p, d; | 922 Vector p, d; |
920 | 923 |
921 const CoordinateSystem3D& slice = otherPlane_.GetSlice(); | 924 const CoordinateSystem3D& slice = otherPlane_.GetSlice(); |
922 | 925 |
923 // Compute the line of intersection between the two slices | 926 // Compute the line of intersection between the two slices |
933 double x1, y1, x2, y2; | 936 double x1, y1, x2, y2; |
934 viewportSlice.ProjectPoint(x1, y1, p); | 937 viewportSlice.ProjectPoint(x1, y1, p); |
935 viewportSlice.ProjectPoint(x2, y2, p + 1000.0 * d); | 938 viewportSlice.ProjectPoint(x2, y2, p + 1000.0 * d); |
936 | 939 |
937 const Extent2D extent = otherPlane_.GetSceneExtent(); | 940 const Extent2D extent = otherPlane_.GetSceneExtent(); |
938 | 941 |
939 if (GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2, | 942 if (GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2, |
940 x1, y1, x2, y2, | 943 x1, y1, x2, y2, |
941 extent.GetX1(), extent.GetY1(), | 944 extent.GetX1(), extent.GetY1(), |
942 extent.GetX2(), extent.GetY2())) | 945 extent.GetX2(), extent.GetY2())) |
943 { | 946 { |