# HG changeset patch # User Sebastien Jodogne # Date 1495794026 -7200 # Node ID bd48431ac285a0f161425b513c83415af995337a # Parent c7537730659816cd0f9cde5796157cd8f6f5dadb fix diff -r c75377306598 -r bd48431ac285 Applications/Samples/SingleFrameApplication.h --- a/Applications/Samples/SingleFrameApplication.h Wed May 24 23:25:36 2017 +0200 +++ b/Applications/Samples/SingleFrameApplication.h Fri May 26 12:20:26 2017 +0200 @@ -22,6 +22,7 @@ #pragma once #include "SampleApplicationBase.h" +#include "SampleInteractor.h" #include "../../Framework/Layers/OrthancFrameLayerSource.h" #include "../../Framework/Widgets/LayerWidget.h" @@ -36,6 +37,61 @@ public IVolumeSlicesObserver { private: + class Interactor : public IWorldSceneInteractor + { + public: + 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) + { + } + + virtual void KeyPressed(WorldSceneWidget& widget, + char key, + KeyboardModifiers modifiers, + IStatusBar* statusBar) + { + switch (key) + { + case 's': + widget.SetDefaultView(); + break; + + default: + break; + } + } + }; + LayerWidget* widget_; public: @@ -49,6 +105,7 @@ slices.GetSliceCount() > 0) { widget_->SetSlice(slices.GetSlice(0)); + widget_->SetDefaultView(); } } @@ -73,6 +130,8 @@ { using namespace OrthancStone; + statusBar.SetMessage("Use the key \"s\" to reinitialize the layout"); + if (parameters.count("instance") != 1) { LOG(ERROR) << "The instance ID is missing"; @@ -84,7 +143,7 @@ std::auto_ptr widget(new LayerWidget); -#if 0 +#if 1 std::auto_ptr layer (new OrthancFrameLayerSource(context.GetWebService(), instance, frame)); layer->SetObserver(*this); @@ -106,17 +165,26 @@ widget->AddLayer(new OrthancFrameLayerSource(context.GetWebService(), "a1c4dc6b-255d27f0-88069875-8daed730-2f5ee5c6", 0)); - RenderStyle s; - //s.drawGrid_ = true; - s.alpha_ = 1; - widget->SetLayerStyle(0, s); - s.alpha_ = 0.5; - s.applyLut_ = true; - s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET; - widget->SetLayerStyle(1, s); + { + RenderStyle s; + s.alpha_ = 1; + widget->SetLayerStyle(0, s); + } + + { + RenderStyle s; + s.drawGrid_ = true; + s.SetColor(255, 0, 0); // Draw missing PET layer in red + s.alpha_ = 0.5; + s.applyLut_ = true; + s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET; + widget->SetLayerStyle(1, s); + } #endif - + widget_ = widget.get(); + widget_->SetTransmitMouseOver(true); + widget_->SetInteractor(context.AddInteractor(new Interactor)); context.SetCentralWidget(widget.release()); } }; diff -r c75377306598 -r bd48431ac285 Framework/Layers/FrameRenderer.cpp --- a/Framework/Layers/FrameRenderer.cpp Wed May 24 23:25:36 2017 +0200 +++ b/Framework/Layers/FrameRenderer.cpp Fri May 26 12:20:26 2017 +0200 @@ -111,7 +111,7 @@ { return true; } - + x1 = 0; y1 = 0; cairo_matrix_transform_point(&transform, &x1, &y1); @@ -239,20 +239,20 @@ ILayerRenderer* FrameRenderer::CreateRenderer(Orthanc::ImageAccessor* frame, - const Slice& slice, + const Slice& frameSlice, bool isFullQuality) { std::auto_ptr protect(frame); if (frame->GetFormat() == Orthanc::PixelFormat_RGB24) { - return new ColorFrameRenderer(protect.release(), slice.GetGeometry(), - slice.GetPixelSpacingX(), slice.GetPixelSpacingY(), isFullQuality); + return new ColorFrameRenderer(protect.release(), frameSlice.GetGeometry(), + frameSlice.GetPixelSpacingX(), frameSlice.GetPixelSpacingY(), isFullQuality); } else { - return new GrayscaleFrameRenderer(protect.release(), slice.GetConverter(), slice.GetGeometry(), - slice.GetPixelSpacingX(), slice.GetPixelSpacingY(), isFullQuality); + return new GrayscaleFrameRenderer(protect.release(), frameSlice.GetConverter(), frameSlice.GetGeometry(), + frameSlice.GetPixelSpacingX(), frameSlice.GetPixelSpacingY(), isFullQuality); } } } diff -r c75377306598 -r bd48431ac285 Framework/Layers/FrameRenderer.h --- a/Framework/Layers/FrameRenderer.h Wed May 24 23:25:36 2017 +0200 +++ b/Framework/Layers/FrameRenderer.h Fri May 26 12:20:26 2017 +0200 @@ -65,11 +65,11 @@ double& x2, double& y2, const SliceGeometry& viewportSlice, - const Slice& slice) + const Slice& frame) { return ComputeFrameExtent(x1, y1, x2, y2, viewportSlice, - slice.GetGeometry(), slice.GetWidth(), slice.GetHeight(), - slice.GetPixelSpacingX(), slice.GetPixelSpacingY()); + frame.GetGeometry(), frame.GetWidth(), frame.GetHeight(), + frame.GetPixelSpacingX(), frame.GetPixelSpacingY()); } virtual bool RenderLayer(CairoContext& context, @@ -92,7 +92,7 @@ bool isFullQuality); static ILayerRenderer* CreateRenderer(Orthanc::ImageAccessor* frame, - const Slice& slice, + const Slice& frameSlice, bool isFullQuality); }; } diff -r c75377306598 -r bd48431ac285 Framework/Layers/OrthancFrameLayerSource.cpp --- a/Framework/Layers/OrthancFrameLayerSource.cpp Wed May 24 23:25:36 2017 +0200 +++ b/Framework/Layers/OrthancFrameLayerSource.cpp Fri May 26 12:20:26 2017 +0200 @@ -48,6 +48,8 @@ } } + LayerSourceBase::NotifyGeometryReady(); + if (observer2_ != NULL) { ParallelSlices slices; @@ -59,8 +61,6 @@ observer2_->NotifySlicesAvailable(slices); } - - LayerSourceBase::NotifyGeometryReady(); } void OrthancFrameLayerSource::NotifyGeometryError(const OrthancSlicesLoader& loader) @@ -123,12 +123,11 @@ double& y1, double& x2, double& y2, - const SliceGeometry& viewportSlice /* ignored */) + const SliceGeometry& viewportSlice) { bool ok = false; - if (IsStarted() && - loader_.IsGeometryReady()) + if (loader_.IsGeometryReady()) { double tx1, ty1, tx2, ty2; @@ -164,12 +163,8 @@ { size_t index; - if (!IsStarted() || - !loader_.IsGeometryReady()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else if (loader_.LookupSlice(index, viewportSlice)) + if (loader_.IsGeometryReady() && + loader_.LookupSlice(index, viewportSlice)) { loader_.ScheduleLoadSliceImage(index); } diff -r c75377306598 -r bd48431ac285 Framework/Toolbox/Slice.h --- a/Framework/Toolbox/Slice.h Wed May 24 23:25:36 2017 +0200 +++ b/Framework/Toolbox/Slice.h Fri May 26 12:20:26 2017 +0200 @@ -32,6 +32,7 @@ enum Type { Type_Invalid, + Type_Detached, Type_OrthancInstance // TODO A slice could come from some DICOM file (URL) }; @@ -52,6 +53,21 @@ { } + // TODO Is this constructor the best way to go to tackle missing + // layers within LayerWidget? + Slice(const SliceGeometry& plane, + double thickness) : + type_(Type_Detached), + frame_(0), + geometry_(plane), + pixelSpacingX_(1), + pixelSpacingY_(1), + thickness_(thickness), + width_(0), + height_(0) + { + } + bool ParseOrthancFrame(const OrthancPlugins::IDicomDataset& dataset, const std::string& instanceId, unsigned int frame); diff -r c75377306598 -r bd48431ac285 Framework/Widgets/LayerWidget.cpp --- a/Framework/Widgets/LayerWidget.cpp Wed May 24 23:25:36 2017 +0200 +++ b/Framework/Widgets/LayerWidget.cpp Fri May 26 12:20:26 2017 +0200 @@ -22,6 +22,9 @@ #include "LayerWidget.h" #include "../../Resources/Orthanc/Core/Logging.h" +#include "../Layers/MissingLayerRenderer.h" + +static const double THIN_SLICE_THICKNESS = 100.0 * std::numeric_limits::epsilon(); namespace OrthancStone { @@ -158,6 +161,33 @@ } } + + bool LayerWidget::GetAndFixExtent(double& x1, + double& y1, + double& x2, + double& y2, + ILayerSource& source) const + { + if (source.GetExtent(x1, y1, x2, y2, slice_)) + { + if (x1 > x2) + { + std::swap(x1, x2); + } + + if (y1 > y2) + { + std::swap(y1, y2); + } + + return true; + } + else + { + return false; + } + } + void LayerWidget::GetSceneExtent(double& x1, double& y1, @@ -171,18 +201,8 @@ double ax, ay, bx, by; assert(layers_[i] != NULL); - if (layers_[i]->GetExtent(ax, ay, bx, by, slice_)) + if (GetAndFixExtent(ax, ay, bx, by, *layers_[i])) { - if (ax > bx) - { - std::swap(ax, bx); - } - - if (ay > by) - { - std::swap(ay, by); - } - LOG(INFO) << "Extent of layer " << i << ": (" << ax << "," << ay << ")->(" << bx << "," << by << ")"; if (first) @@ -353,7 +373,7 @@ void LayerWidget::SetSlice(const SliceGeometry& slice) { - if (!slice_.IsSamePlane(slice, 100.0 * std::numeric_limits::epsilon())) + if (!slice_.IsSamePlane(slice, THIN_SLICE_THICKNESS)) { if (currentScene_.get() == NULL || (pendingScene_.get() != NULL && @@ -365,13 +385,10 @@ slice_ = slice; ResetPendingScene(); - if (started_) + for (size_t i = 0; i < layers_.size(); i++) { - for (size_t i = 0; i < layers_.size(); i++) - { - assert(layers_[i] != NULL); - layers_[i]->ScheduleLayerCreation(slice_); - } + assert(layers_[i] != NULL); + layers_[i]->ScheduleLayerCreation(slice_); } } } @@ -383,7 +400,6 @@ if (LookupLayer(i, source)) { LOG(INFO) << "Geometry ready for layer " << i; - SetDefaultView(); layers_[i]->ScheduleLayerCreation(slice_); } } @@ -418,7 +434,8 @@ std::auto_ptr tmp(renderer); size_t index; - if (LookupLayer(index, source)) + if (LookupLayer(index, source) && + slice.ContainsPlane(slice_)) // Whether the slice comes from an older request { LOG(INFO) << "Renderer ready for layer " << index; UpdateLayer(index, tmp.release(), slice); @@ -427,11 +444,21 @@ void LayerWidget::NotifyLayerError(ILayerSource& source, - const SliceGeometry& viewportSlice) + const SliceGeometry& slice) { - size_t i; - if (LookupLayer(i, source)) - LOG(ERROR) << "Error on layer " << i; + size_t index; + + if (LookupLayer(index, source) && + slice.IsSamePlane(slice_, THIN_SLICE_THICKNESS)) // Whether the slice comes from an older request + { + LOG(ERROR) << "Error on layer " << index; + + double x1, y1, x2, y2; + if (GetAndFixExtent(x1, y1, x2, y2, source)) + { + UpdateLayer(index, new MissingLayerRenderer(x1, y1, x2, y2), Slice(slice, THIN_SLICE_THICKNESS)); + } + } } diff -r c75377306598 -r bd48431ac285 Framework/Widgets/LayerWidget.h --- a/Framework/Widgets/LayerWidget.h Wed May 24 23:25:36 2017 +0200 +++ b/Framework/Widgets/LayerWidget.h Fri May 26 12:20:26 2017 +0200 @@ -48,7 +48,12 @@ bool LookupLayer(size_t& index /* out */, ILayerSource& layer) const; - + + bool GetAndFixExtent(double& x1, + double& y1, + double& x2, + double& y2, + ILayerSource& source) const; virtual void NotifyGeometryReady(ILayerSource& source); @@ -94,6 +99,11 @@ void SetSlice(const SliceGeometry& slice); + const SliceGeometry& GetSlice() const + { + return slice_; + } + virtual void Start(); }; } diff -r c75377306598 -r bd48431ac285 Framework/Widgets/WidgetBase.cpp --- a/Framework/Widgets/WidgetBase.cpp Wed May 24 23:25:36 2017 +0200 +++ b/Framework/Widgets/WidgetBase.cpp Fri May 26 12:20:26 2017 +0200 @@ -105,7 +105,8 @@ parent_(NULL), viewport_(NULL), statusBar_(NULL), - backgroundCleared_(false) + backgroundCleared_(false), + transmitMouseOver_(false) { backgroundColor_[0] = 0; backgroundColor_[1] = 0; diff -r c75377306598 -r bd48431ac285 Framework/Widgets/WidgetBase.h --- a/Framework/Widgets/WidgetBase.h Wed May 24 23:25:36 2017 +0200 +++ b/Framework/Widgets/WidgetBase.h Fri May 26 12:20:26 2017 +0200 @@ -35,6 +35,7 @@ IStatusBar* statusBar_; bool backgroundCleared_; uint8_t backgroundColor_[3]; + bool transmitMouseOver_; protected: void ClearBackgroundOrthanc(Orthanc::ImageAccessor& target) const; @@ -71,6 +72,11 @@ return backgroundCleared_; } + void SetTransmitMouseOver(bool transmit) + { + transmitMouseOver_ = transmit; + } + void SetBackgroundColor(uint8_t red, uint8_t green, uint8_t blue); @@ -95,7 +101,7 @@ virtual bool HasRenderMouseOver() { - return false; + return transmitMouseOver_; } virtual void NotifyChange(); diff -r c75377306598 -r bd48431ac285 Framework/Widgets/WorldSceneWidget.cpp --- a/Framework/Widgets/WorldSceneWidget.cpp Wed May 24 23:25:36 2017 +0200 +++ b/Framework/Widgets/WorldSceneWidget.cpp Fri May 26 12:20:26 2017 +0200 @@ -21,8 +21,6 @@ #include "WorldSceneWidget.h" -#include "../../Resources/Orthanc/Core/OrthancException.h" - namespace OrthancStone { static void MapMouseToScene(double& sceneX,