Mercurial > hg > orthanc-stone
comparison Applications/Samples/SingleFrameEditorApplication.h @ 340:f5d5814a41a0 am-2
rendering BitmapStack
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sat, 20 Oct 2018 18:26:05 +0200 |
parents | 5a7915b23138 |
children | 7bebbfa56bde |
comparison
equal
deleted
inserted
replaced
339:5a7915b23138 | 340:f5d5814a41a0 |
---|---|
33 #include <Core/Logging.h> | 33 #include <Core/Logging.h> |
34 #include <Core/Toolbox.h> | 34 #include <Core/Toolbox.h> |
35 #include <Plugins/Samples/Common/FullOrthancDataset.h> | 35 #include <Plugins/Samples/Common/FullOrthancDataset.h> |
36 #include <Plugins/Samples/Common/DicomDatasetReader.h> | 36 #include <Plugins/Samples/Common/DicomDatasetReader.h> |
37 | 37 |
38 | |
39 #include <boost/math/constants/constants.hpp> | |
40 | |
38 namespace OrthancStone | 41 namespace OrthancStone |
39 { | 42 { |
40 class BitmapStack : | 43 class BitmapStack : |
41 public IObserver, | 44 public IObserver, |
42 public IObservable | 45 public IObservable |
83 void AddToExtent(Extent2D& extent, | 86 void AddToExtent(Extent2D& extent, |
84 double x, | 87 double x, |
85 double y) const | 88 double y) const |
86 { | 89 { |
87 Vector p; | 90 Vector p; |
88 LinearAlgebra::AssignVector(p, x, y, 0); | 91 LinearAlgebra::AssignVector(p, x, y, 1); |
89 | 92 |
90 Vector q = LinearAlgebra::Product(transform_, p); | 93 Vector q = LinearAlgebra::Product(transform_, p); |
91 | 94 |
92 if (!LinearAlgebra::IsCloseToZero(q[2])) | 95 if (!LinearAlgebra::IsNear(q[2], 1.0)) |
93 { | 96 { |
94 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 97 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
95 } | 98 } |
96 else | 99 else |
97 { | 100 { |
182 { | 185 { |
183 transform_(0, 0) = pixelSpacing[0]; | 186 transform_(0, 0) = pixelSpacing[0]; |
184 transform_(1, 1) = pixelSpacing[1]; | 187 transform_(1, 1) = pixelSpacing[1]; |
185 } | 188 } |
186 | 189 |
190 | |
191 #if 0 | |
192 double a = 10.0 / 180.0 * boost::math::constants::pi<double>(); | |
193 Matrix m; | |
194 const double v[] = { cos(a), -sin(a), 0, | |
195 sin(a), cos(a), 0, | |
196 0, 0, 1 }; | |
197 LinearAlgebra::FillMatrix(m, 3, 3, v); | |
198 transform_ = LinearAlgebra::Product(m, transform_); | |
199 | |
200 #else | |
201 static unsigned int c = 0; | |
202 if (c == 0) | |
203 { | |
204 transform_(0, 2) = 400; | |
205 c ++; | |
206 } | |
207 #endif | |
208 | |
187 OrthancPlugins::DicomDatasetReader reader(dataset); | 209 OrthancPlugins::DicomDatasetReader reader(dataset); |
188 | 210 |
189 if (!reader.GetUnsignedIntegerValue(width_, ConvertTag(Orthanc::DICOM_TAG_COLUMNS)) || | 211 if (!reader.GetUnsignedIntegerValue(width_, ConvertTag(Orthanc::DICOM_TAG_COLUMNS)) || |
190 !reader.GetUnsignedIntegerValue(height_, ConvertTag(Orthanc::DICOM_TAG_ROWS))) | 212 !reader.GetUnsignedIntegerValue(height_, ConvertTag(Orthanc::DICOM_TAG_ROWS))) |
191 { | 213 { |
242 void Render(Orthanc::ImageAccessor& buffer, | 264 void Render(Orthanc::ImageAccessor& buffer, |
243 const ViewportGeometry& view) const | 265 const ViewportGeometry& view) const |
244 { | 266 { |
245 if (converted_.get() != NULL) | 267 if (converted_.get() != NULL) |
246 { | 268 { |
247 ApplyProjectiveTransform(buffer, *converted_, transform_, ImageInterpolation_Nearest); // TODO | 269 Matrix m = LinearAlgebra::Product(view.GetMatrix(), transform_); |
270 ApplyProjectiveTransform(buffer, *converted_, m, ImageInterpolation_Bilinear, false); | |
248 } | 271 } |
249 } | 272 } |
250 }; | 273 }; |
251 | 274 |
252 | 275 |
400 | 423 |
401 | 424 |
402 Extent2D GetSceneExtent() const | 425 Extent2D GetSceneExtent() const |
403 { | 426 { |
404 Extent2D extent; | 427 Extent2D extent; |
405 | 428 |
406 for (Bitmaps::const_iterator it = bitmaps_.begin(); | 429 for (Bitmaps::const_iterator it = bitmaps_.begin(); |
407 it != bitmaps_.end(); ++it) | 430 it != bitmaps_.end(); ++it) |
408 { | 431 { |
409 assert(it->second != NULL); | 432 assert(it->second != NULL); |
410 extent.Union(it->second->GetExtent()); | 433 extent.Union(it->second->GetExtent()); |
411 } | 434 } |
412 | 435 |
413 printf("(%.02f,%.02f) (%.02f,%.02f) \n", | |
414 extent.GetX1(), extent.GetY1(), | |
415 extent.GetX2(), extent.GetY2()); | |
416 | |
417 return extent; | 436 return extent; |
418 } | 437 } |
419 | 438 |
420 | 439 |
421 void Render(Orthanc::ImageAccessor& buffer, | 440 void Render(Orthanc::ImageAccessor& buffer, |
449 } | 468 } |
450 | 469 |
451 virtual bool RenderScene(CairoContext& context, | 470 virtual bool RenderScene(CairoContext& context, |
452 const ViewportGeometry& view) | 471 const ViewportGeometry& view) |
453 { | 472 { |
454 Orthanc::Image buffer(Orthanc::PixelFormat_Float32, context.GetWidth(), context.GetHeight(), false); | 473 // "Render()" has been replaced |
455 stack_.Render(buffer, view); | 474 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
456 | 475 } |
457 // As in GrayscaleFrameRenderer | 476 |
477 public: | |
478 BitmapStackWidget(MessageBroker& broker, | |
479 BitmapStack& stack, | |
480 const std::string& name) : | |
481 WorldSceneWidget(name), | |
482 IObservable(broker), | |
483 IObserver(broker), | |
484 stack_(stack) | |
485 { | |
486 stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::GeometryChangedMessage>(*this, &BitmapStackWidget::OnGeometryChanged)); | |
487 stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::ContentChangedMessage>(*this, &BitmapStackWidget::OnContentChanged)); | |
488 } | |
489 | |
490 void OnGeometryChanged(const BitmapStack::GeometryChangedMessage& message) | |
491 { | |
492 printf("Geometry has changed\n"); | |
493 FitContent(); | |
494 } | |
495 | |
496 void OnContentChanged(const BitmapStack::ContentChangedMessage& message) | |
497 { | |
498 printf("Content has changed\n"); | |
499 NotifyContentChanged(); | |
500 } | |
501 | |
502 virtual bool Render(Orthanc::ImageAccessor& target) | |
503 { | |
504 Orthanc::Image buffer(Orthanc::PixelFormat_Float32, target.GetWidth(), target.GetHeight(), false); | |
505 stack_.Render(buffer, GetView()); | |
506 | |
507 // As in GrayscaleFrameRenderer => TODO MERGE | |
458 | 508 |
459 float windowCenter, windowWidth; | 509 float windowCenter, windowWidth; |
460 stack_.GetWindowing(windowCenter, windowWidth); | 510 stack_.GetWindowing(windowCenter, windowWidth); |
461 | 511 |
462 float x0 = windowCenter - windowWidth / 2.0f; | 512 float x0 = windowCenter - windowWidth / 2.0f; |
463 float x1 = windowCenter + windowWidth / 2.0f; | 513 float x1 = windowCenter + windowWidth / 2.0f; |
464 | 514 |
465 CairoSurface cairo(context.GetWidth(), context.GetHeight()); | 515 const unsigned int width = target.GetWidth(); |
466 | 516 const unsigned int height = target.GetHeight(); |
467 Orthanc::ImageAccessor target; | |
468 cairo.GetAccessor(target); | |
469 | |
470 const unsigned int width = cairo.GetWidth(); | |
471 const unsigned int height = cairo.GetHeight(); | |
472 | 517 |
473 for (unsigned int y = 0; y < height; y++) | 518 for (unsigned int y = 0; y < height; y++) |
474 { | 519 { |
475 const float* p = reinterpret_cast<const float*>(buffer.GetConstRow(y)); | 520 const float* p = reinterpret_cast<const float*>(buffer.GetConstRow(y)); |
476 uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y)); | 521 uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y)); |
494 v = static_cast<uint8_t>(255.0f * (*p - x0) / (x1 - x0)); | 539 v = static_cast<uint8_t>(255.0f * (*p - x0) / (x1 - x0)); |
495 } | 540 } |
496 | 541 |
497 // TODO MONOCHROME1 | 542 // TODO MONOCHROME1 |
498 /*if (invert_) | 543 /*if (invert_) |
499 { | 544 { |
500 v = 255 - v; | 545 v = 255 - v; |
501 }*/ | 546 }*/ |
502 } | 547 } |
503 | 548 |
504 q[3] = 255; | 549 q[3] = 255; |
505 q[2] = v; | 550 q[2] = v; |
506 q[1] = v; | 551 q[1] = v; |
507 q[0] = 128; | 552 q[0] = v; |
508 } | 553 } |
509 } | 554 } |
510 | |
511 | |
512 | |
513 cairo_t* cr = context.GetObject(); | |
514 | |
515 // Clear background | |
516 cairo_set_source_rgb(cr, 0, 0, 0); | |
517 cairo_paint(cr); | |
518 | |
519 #if 1 | |
520 cairo_save(cr); | |
521 cairo_set_source_surface(cr, cairo.GetObject(), 0, 0); | |
522 cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); //TODO | |
523 cairo_paint(cr); | |
524 cairo_restore(cr); | |
525 #else | |
526 Extent2D extent = stack_.GetSceneExtent(); | |
527 | |
528 float color = 0.5; | |
529 cairo_set_source_rgb(cr, 0, 1.0f - color, color); | |
530 cairo_rectangle(cr, extent.GetX1(), extent.GetY1(), extent.GetX2(), extent.GetY2()); | |
531 cairo_fill(cr); | |
532 #endif | |
533 | 555 |
534 return true; | 556 return true; |
535 } | 557 } |
536 | 558 |
537 public: | |
538 BitmapStackWidget(MessageBroker& broker, | |
539 BitmapStack& stack, | |
540 const std::string& name) : | |
541 WorldSceneWidget(name), | |
542 IObservable(broker), | |
543 IObserver(broker), | |
544 stack_(stack) | |
545 { | |
546 stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::GeometryChangedMessage>(*this, &BitmapStackWidget::OnGeometryChanged)); | |
547 stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::ContentChangedMessage>(*this, &BitmapStackWidget::OnContentChanged)); | |
548 } | |
549 | |
550 void OnGeometryChanged(const BitmapStack::GeometryChangedMessage& message) | |
551 { | |
552 printf("Geometry has changed\n"); | |
553 FitContent(); | |
554 } | |
555 | |
556 void OnContentChanged(const BitmapStack::ContentChangedMessage& message) | |
557 { | |
558 printf("Content has changed\n"); | |
559 NotifyContentChanged(); | |
560 } | |
561 }; | 559 }; |
562 | 560 |
563 | 561 |
564 namespace Samples | 562 namespace Samples |
565 { | 563 { |
566 class SingleFrameEditorApplication : | 564 class SingleFrameEditorApplication : |
567 public SampleSingleCanvasApplicationBase, | 565 public SampleSingleCanvasApplicationBase, |
568 public IObserver | 566 public IObserver |
569 { | 567 { |
570 enum Tools | 568 enum Tools |
571 { | 569 { |
572 Tools_Crop, | 570 Tools_Crop, |
573 Tools_Windowing, | 571 Tools_Windowing, |
601 double x, | 599 double x, |
602 double y, | 600 double y, |
603 IStatusBar* statusBar) | 601 IStatusBar* statusBar) |
604 { | 602 { |
605 switch (application_.currentTool_) { | 603 switch (application_.currentTool_) { |
606 case Tools_Zoom: | 604 case Tools_Zoom: |
607 printf("ZOOM\n"); | 605 printf("ZOOM\n"); |
608 | 606 |
609 case Tools_Crop: | 607 case Tools_Crop: |
610 case Tools_Windowing: | 608 case Tools_Windowing: |
611 case Tools_Pan: | 609 case Tools_Pan: |
612 // TODO return the right mouse tracker | 610 // TODO return the right mouse tracker |
613 return NULL; | 611 return NULL; |
614 } | 612 } |
615 | 613 |
616 return NULL; | 614 return NULL; |
617 } | 615 } |
618 | 616 |
644 KeyboardModifiers modifiers, | 642 KeyboardModifiers modifiers, |
645 IStatusBar* statusBar) | 643 IStatusBar* statusBar) |
646 { | 644 { |
647 switch (keyChar) | 645 switch (keyChar) |
648 { | 646 { |
649 case 's': | 647 case 's': |
650 widget.FitContent(); | 648 widget.FitContent(); |
651 break; | 649 break; |
652 case 'p': | 650 case 'p': |
653 application_.currentTool_ = Tools_Pan; | 651 application_.currentTool_ = Tools_Pan; |
654 break; | 652 break; |
655 case 'z': | 653 case 'z': |
656 application_.currentTool_ = Tools_Zoom; | 654 application_.currentTool_ = Tools_Zoom; |
657 break; | 655 break; |
658 case 'c': | 656 case 'c': |
659 application_.currentTool_ = Tools_Crop; | 657 application_.currentTool_ = Tools_Crop; |
660 break; | 658 break; |
661 case 'w': | 659 case 'w': |
662 application_.currentTool_ = Tools_Windowing; | 660 application_.currentTool_ = Tools_Windowing; |
663 break; | 661 break; |
664 case 'i': | 662 case 'i': |
665 application_.Invert(); | 663 application_.Invert(); |
666 break; | 664 break; |
667 case 'r': | 665 case 'r': |
668 if (modifiers == KeyboardModifiers_None) | 666 if (modifiers == KeyboardModifiers_None) |
669 application_.Rotate(90); | 667 application_.Rotate(90); |
670 else | 668 else |
671 application_.Rotate(-90); | 669 application_.Rotate(-90); |
672 break; | 670 break; |
673 case 'e': | 671 case 'e': |
674 application_.Export(); | 672 application_.Export(); |
675 break; | 673 break; |
676 default: | 674 default: |
677 break; | 675 break; |
678 } | 676 } |
679 } | 677 } |
680 }; | 678 }; |
681 | 679 |
682 std::auto_ptr<Interactor> mainWidgetInteractor_; | 680 std::auto_ptr<Interactor> mainWidgetInteractor_; |
697 | 695 |
698 virtual void DeclareStartupOptions(boost::program_options::options_description& options) | 696 virtual void DeclareStartupOptions(boost::program_options::options_description& options) |
699 { | 697 { |
700 boost::program_options::options_description generic("Sample options"); | 698 boost::program_options::options_description generic("Sample options"); |
701 generic.add_options() | 699 generic.add_options() |
702 ("instance", boost::program_options::value<std::string>(), | 700 ("instance", boost::program_options::value<std::string>(), |
703 "Orthanc ID of the instance") | 701 "Orthanc ID of the instance") |
704 ("frame", boost::program_options::value<unsigned int>()->default_value(0), | 702 ("frame", boost::program_options::value<unsigned int>()->default_value(0), |
705 "Number of the frame, for multi-frame DICOM instances") | 703 "Number of the frame, for multi-frame DICOM instances") |
706 ; | 704 ; |
707 | 705 |
708 options.add(generic); | 706 options.add(generic); |
709 } | 707 } |
710 | 708 |
711 virtual void Initialize(StoneApplicationContext* context, | 709 virtual void Initialize(StoneApplicationContext* context, |
729 | 727 |
730 orthancApiClient_.reset(new OrthancApiClient(IObserver::broker_, context_->GetWebService())); | 728 orthancApiClient_.reset(new OrthancApiClient(IObserver::broker_, context_->GetWebService())); |
731 | 729 |
732 stack_.reset(new BitmapStack(IObserver::broker_, *orthancApiClient_)); | 730 stack_.reset(new BitmapStack(IObserver::broker_, *orthancApiClient_)); |
733 stack_->LoadFrame(instance, frame, false); | 731 stack_->LoadFrame(instance, frame, false); |
734 //stack_->LoadFrame(instance, frame, false); | 732 stack_->LoadFrame("61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", frame, false); |
735 | 733 |
736 mainWidget_ = new BitmapStackWidget(IObserver::broker_, *stack_, "main-widget"); | 734 mainWidget_ = new BitmapStackWidget(IObserver::broker_, *stack_, "main-widget"); |
737 mainWidget_->SetTransmitMouseOver(true); | 735 mainWidget_->SetTransmitMouseOver(true); |
738 | 736 |
739 mainWidgetInteractor_.reset(new Interactor(*this)); | 737 mainWidgetInteractor_.reset(new Interactor(*this)); |