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));