# HG changeset patch # User Sebastien Jodogne # Date 1496306029 -7200 # Node ID eccd64f8e2977f00216293f84de1fcb30677aab3 # Parent 474d85e7649958dc9f8af8c8026d653ab0ab0d11 VolumeImageInteractor diff -r 474d85e76499 -r eccd64f8e297 Applications/Samples/SingleVolumeApplication.h --- a/Applications/Samples/SingleVolumeApplication.h Wed May 31 18:05:33 2017 +0200 +++ b/Applications/Samples/SingleVolumeApplication.h Thu Jun 01 10:33:49 2017 +0200 @@ -36,338 +36,9 @@ namespace Samples { class SingleVolumeApplication : - public SampleApplicationBase, - private ILayerSource::IObserver + public SampleApplicationBase { - private: - class Interactor : public IWorldSceneInteractor - { - private: - SingleVolumeApplication& application_; - - public: - Interactor(SingleVolumeApplication& application) : - application_(application) - { - } - - virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, - const ViewportGeometry& view, - MouseButton button, - double x, - double y, - IStatusBar* statusBar) - { - return NULL; - } - - virtual void MouseOver(CairoContext& context, - WorldSceneWidget& widget, - const ViewportGeometry& view, - double x, - double y, - IStatusBar* statusBar) - { - if (statusBar != NULL) - { - Vector p = dynamic_cast(widget).GetSlice().MapSliceToWorldCoordinates(x, y); - - char buf[64]; - sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)", - p[0] / 10.0, p[1] / 10.0, p[2] / 10.0); - statusBar->SetMessage(buf); - } - } - - virtual void MouseWheel(WorldSceneWidget& widget, - MouseWheelDirection direction, - KeyboardModifiers modifiers, - IStatusBar* statusBar) - { - int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1); - - switch (direction) - { - case MouseWheelDirection_Up: - application_.OffsetSlice(-scale); - break; - - case MouseWheelDirection_Down: - application_.OffsetSlice(scale); - break; - - default: - break; - } - } - - virtual void KeyPressed(WorldSceneWidget& widget, - char key, - KeyboardModifiers modifiers, - IStatusBar* statusBar) - { - switch (key) - { - case 's': - widget.SetDefaultView(); - break; - - default: - break; - } - } - }; - - - LayerWidget* widget_; - const OrthancVolumeImage* volume_; - VolumeProjection projection_; - std::auto_ptr slices_; - size_t slice_; - - void OffsetSlice(int offset) - { - if (slices_.get() != NULL) - { - int slice = static_cast(slice_) + offset; - - if (slice < 0) - { - slice = 0; - } - - if (slice >= static_cast(slices_->GetSliceCount())) - { - slice = slices_->GetSliceCount() - 1; - } - - if (slice != static_cast(slice_)) - { - SetSlice(slice); - } - } - } - - void SetSlice(size_t slice) - { - if (slices_.get() != NULL) - { - slice_ = slice; - widget_->SetSlice(slices_->GetSlice(slice_).GetGeometry()); - } - } - - virtual void NotifyGeometryReady(const ILayerSource& source) - { - if (slices_.get() == NULL) - { - slices_.reset(new VolumeImageGeometry(*volume_, projection_)); - SetSlice(slices_->GetSliceCount() / 2); - - widget_->SetDefaultView(); - } - } - - virtual void NotifyGeometryError(const ILayerSource& source) - { - } - - virtual void NotifyContentChange(const ILayerSource& source) - { - } - - virtual void NotifySliceChange(const ILayerSource& source, - const Slice& slice) - { - } - - virtual void NotifyLayerReady(std::auto_ptr& layer, - const ILayerSource& source, - const Slice& slice, - bool isError) - { - } - -#if 0 - class Interactor : public SampleInteractor - { - private: - enum MouseMode - { - MouseMode_None, - MouseMode_TrackCoordinates, - MouseMode_LineMeasure, - MouseMode_CircleMeasure - }; - - MouseMode mouseMode_; - - void SetMouseMode(MouseMode mode, - IStatusBar* statusBar) - { - if (mouseMode_ == mode) - { - mouseMode_ = MouseMode_None; - } - else - { - mouseMode_ = mode; - } - - if (statusBar) - { - switch (mouseMode_) - { - case MouseMode_None: - statusBar->SetMessage("Disabling the mouse tools"); - break; - - case MouseMode_TrackCoordinates: - statusBar->SetMessage("Tracking the mouse coordinates"); - break; - - case MouseMode_LineMeasure: - statusBar->SetMessage("Mouse clicks will now measure the distances"); - break; - - case MouseMode_CircleMeasure: - statusBar->SetMessage("Mouse clicks will now draw circles"); - break; - - default: - break; - } - } - } - - public: - Interactor(VolumeImage& volume, - VolumeProjection projection, - bool reverse) : - SampleInteractor(volume, projection, reverse), - mouseMode_(MouseMode_None) - { - } - - virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, - const SliceGeometry& slice, - const ViewportGeometry& view, - MouseButton button, - double x, - double y, - IStatusBar* statusBar) - { - if (button == MouseButton_Left) - { - switch (mouseMode_) - { - case MouseMode_LineMeasure: - return new LineMeasureTracker(NULL, slice, x, y, 255, 0, 0, 14 /* font size */); - - case MouseMode_CircleMeasure: - return new CircleMeasureTracker(NULL, slice, x, y, 255, 0, 0, 14 /* font size */); - - default: - break; - } - } - - return NULL; - } - - virtual void MouseOver(CairoContext& context, - WorldSceneWidget& widget, - const SliceGeometry& slice, - const ViewportGeometry& view, - double x, - double y, - IStatusBar* statusBar) - { - if (mouseMode_ == MouseMode_TrackCoordinates && - statusBar != NULL) - { - Vector p = slice.MapSliceToWorldCoordinates(x, y); - - char buf[64]; - sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)", p[0] / 10.0, p[1] / 10.0, p[2] / 10.0); - statusBar->SetMessage(buf); - } - } - - - virtual void KeyPressed(WorldSceneWidget& widget, - char key, - KeyboardModifiers modifiers, - IStatusBar* statusBar) - { - switch (key) - { - case 't': - SetMouseMode(MouseMode_TrackCoordinates, statusBar); - break; - - case 'm': - SetMouseMode(MouseMode_LineMeasure, statusBar); - break; - - case 'c': - SetMouseMode(MouseMode_CircleMeasure, statusBar); - break; - - case 'b': - { - if (statusBar) - { - statusBar->SetMessage("Setting Hounsfield window to bones"); - } - - RenderStyle style; - style.windowing_ = ImageWindowing_Bone; - dynamic_cast(widget).SetLayerStyle(0, style); - break; - } - - case 'l': - { - if (statusBar) - { - statusBar->SetMessage("Setting Hounsfield window to lung"); - } - - RenderStyle style; - style.windowing_ = ImageWindowing_Lung; - dynamic_cast(widget).SetLayerStyle(0, style); - break; - } - - case 'd': - { - if (statusBar) - { - statusBar->SetMessage("Setting Hounsfield window to what is written in the DICOM file"); - } - - RenderStyle style; - style.windowing_ = ImageWindowing_Default; - dynamic_cast(widget).SetLayerStyle(0, style); - break; - } - - default: - break; - } - } - }; -#endif - - public: - SingleVolumeApplication() : - widget_(NULL), - volume_(NULL) - { - } - virtual void DeclareCommandLineOptions(boost::program_options::options_description& options) { boost::program_options::options_description generic("Sample options"); @@ -403,18 +74,19 @@ std::string tmp = parameters["projection"].as(); Orthanc::Toolbox::ToLowerCase(tmp); - + + VolumeProjection projection; if (tmp == "axial") { - projection_ = VolumeProjection_Axial; + projection = VolumeProjection_Axial; } else if (tmp == "sagittal") { - projection_ = VolumeProjection_Sagittal; + projection = VolumeProjection_Sagittal; } else if (tmp == "coronal") { - projection_ = VolumeProjection_Coronal; + projection = VolumeProjection_Coronal; } else { @@ -423,20 +95,17 @@ } std::auto_ptr widget(new LayerWidget); - widget_ = widget.get(); -#if 0 +#if 1 std::auto_ptr volume(new OrthancVolumeImage(context.GetWebService())); volume->ScheduleLoadSeries(series); - volume_ = volume.get(); - { std::auto_ptr source(new VolumeImageSource(*volume)); - source->Register(*this); widget->AddLayer(source.release()); } + context.AddInteractor(new VolumeImageInteractor(*volume, *widget, projection)); context.AddVolume(volume.release()); #else std::auto_ptr ct(new OrthancVolumeImage(context.GetWebService())); @@ -445,17 +114,15 @@ std::auto_ptr pet(new OrthancVolumeImage(context.GetWebService())); pet->ScheduleLoadSeries("aabad2e7-80702b5d-e599d26c-4f13398e-38d58a9e"); - volume_ = pet.get(); - + context.AddInteractor(new VolumeImageInteractor(*pet, *widget, projection)); + { std::auto_ptr source(new VolumeImageSource(*ct)); - //source->Register(*this); widget->AddLayer(source.release()); } { std::auto_ptr source(new VolumeImageSource(*pet)); - source->Register(*this); widget->AddLayer(source.release()); } @@ -466,6 +133,7 @@ RenderStyle s; //s.drawGrid_ = true; s.alpha_ = 1; + s.windowing_ = ImageWindowing_Bone; widget->SetLayerStyle(0, s); } @@ -473,7 +141,7 @@ RenderStyle s; //s.drawGrid_ = true; s.SetColor(255, 0, 0); // Draw missing PET layer in red - s.alpha_ = 0.5; + s.alpha_ = 0.3; s.applyLut_ = true; s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET; s.interpolation_ = ImageInterpolation_Linear; @@ -488,7 +156,6 @@ statusBar.SetMessage("Use the keys \"c\" to draw circles"); widget->SetTransmitMouseOver(true); - widget->SetInteractor(context.AddInteractor(new Interactor(*this))); context.SetCentralWidget(widget.release()); } }; diff -r 474d85e76499 -r eccd64f8e297 Framework/dev.h --- a/Framework/dev.h Wed May 31 18:05:33 2017 +0200 +++ b/Framework/dev.h Thu Jun 01 10:33:49 2017 +0200 @@ -24,6 +24,7 @@ #include "Layers/FrameRenderer.h" #include "Layers/LayerSourceBase.h" #include "Layers/SliceOutlineRenderer.h" +#include "Widgets/LayerWidget.h" #include "Toolbox/DownloadStack.h" #include "Toolbox/OrthancSlicesLoader.h" #include "Volumes/ImageBuffer3D.h" @@ -602,4 +603,160 @@ LayerSourceBase::NotifyLayerReady(NULL, slice, true); } }; + + + class VolumeImageInteractor : + public IWorldSceneInteractor, + private ISlicedVolume::IObserver + { + private: + LayerWidget& widget_; + VolumeProjection projection_; + std::auto_ptr slices_; + size_t slice_; + + virtual void NotifyGeometryReady(const ISlicedVolume& volume) + { + if (slices_.get() == NULL) + { + const OrthancVolumeImage& image = dynamic_cast(volume); + + slices_.reset(new VolumeImageGeometry(image, projection_)); + SetSlice(slices_->GetSliceCount() / 2); + + widget_.SetDefaultView(); + } + } + + virtual void NotifyGeometryError(const ISlicedVolume& volume) + { + } + + virtual void NotifyContentChange(const ISlicedVolume& volume) + { + } + + virtual void NotifySliceChange(const ISlicedVolume& volume, + const size_t& sliceIndex, + const Slice& slice) + { + } + + virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, + const ViewportGeometry& view, + MouseButton button, + double x, + double y, + IStatusBar* statusBar) + { + return NULL; + } + + virtual void MouseOver(CairoContext& context, + WorldSceneWidget& widget, + const ViewportGeometry& view, + double x, + double y, + IStatusBar* statusBar) + { + } + + virtual void MouseWheel(WorldSceneWidget& widget, + MouseWheelDirection direction, + KeyboardModifiers modifiers, + IStatusBar* statusBar) + { + int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1); + + switch (direction) + { + case MouseWheelDirection_Up: + OffsetSlice(-scale); + break; + + case MouseWheelDirection_Down: + OffsetSlice(scale); + break; + + default: + break; + } + } + + virtual void KeyPressed(WorldSceneWidget& widget, + char key, + KeyboardModifiers modifiers, + IStatusBar* statusBar) + { + switch (key) + { + case 's': + widget.SetDefaultView(); + break; + + default: + break; + } + } + + public: + VolumeImageInteractor(OrthancVolumeImage& volume, + LayerWidget& widget, + VolumeProjection projection) : + widget_(widget), + projection_(projection) + { + volume.Register(*this); + widget.SetInteractor(*this); + } + + bool IsGeometryReady() const + { + return slices_.get() != NULL; + } + + size_t GetSliceCount() const + { + if (slices_.get() == NULL) + { + return 0; + } + else + { + return slices_->GetSliceCount(); + } + } + + void OffsetSlice(int offset) + { + if (slices_.get() != NULL) + { + int slice = static_cast(slice_) + offset; + + if (slice < 0) + { + slice = 0; + } + + if (slice >= static_cast(slices_->GetSliceCount())) + { + slice = slices_->GetSliceCount() - 1; + } + + if (slice != static_cast(slice_)) + { + SetSlice(slice); + } + } + } + + void SetSlice(size_t slice) + { + if (slices_.get() != NULL) + { + slice_ = slice; + widget_.SetSlice(slices_->GetSlice(slice_).GetGeometry()); + } + } + }; }