# HG changeset patch # User am@osimis.io # Date 1539011408 -7200 # Node ID 3a4ca166fafa52ebfdbb33e3392ac675a9e970c0 # Parent b66d13708f40582fb682d553adf3e3cce1646ff7 ImageAccessor refactoring + implemented Image Cache in SmartLoader diff -r b66d13708f40 -r 3a4ca166fafa Applications/Qt/QCairoWidget.cpp --- a/Applications/Qt/QCairoWidget.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Applications/Qt/QCairoWidget.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -50,7 +50,8 @@ { OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_); OrthancStone::IViewport& viewport = context_->GetCentralViewport(); - Orthanc::ImageAccessor a = surface_.GetAccessor(); + Orthanc::ImageAccessor a; + surface_.GetAccessor(a); viewport.Render(a); painter.drawImage(0, 0, *image_); } diff -r b66d13708f40 -r 3a4ca166fafa Applications/Samples/SimpleViewerApplication.h --- a/Applications/Samples/SimpleViewerApplication.h Fri Oct 05 11:57:36 2018 +0200 +++ b/Applications/Samples/SimpleViewerApplication.h Mon Oct 08 17:10:08 2018 +0200 @@ -173,9 +173,12 @@ #if ORTHANC_ENABLE_WASM==1 class SimpleViewerApplicationAdapter : public WasmPlatformApplicationAdapter { + SimpleViewerApplication& viewerApplication_; + public: SimpleViewerApplicationAdapter(MessageBroker& broker, SimpleViewerApplication& application) - : WasmPlatformApplicationAdapter(broker, application) + : WasmPlatformApplicationAdapter(broker, application), + viewerApplication_(application) { } @@ -183,12 +186,12 @@ virtual void HandleMessageFromWeb(std::string& output, const std::string& input) { if (input == "select-tool:line-measure") { - application.currentTool_ = Tools_LineMeasure; + viewerApplication_.currentTool_ = Tools_LineMeasure; NotifyStatusUpdateFromCppToWeb("currentTool=line-measure"); } else if (input == "select-tool:circle-measure") { - application.currentTool_ = Tools_CircleMeasure; + viewerApplication_.currentTool_ = Tools_CircleMeasure; NotifyStatusUpdateFromCppToWeb("currentTool=circle-measure"); } @@ -350,7 +353,7 @@ // if this is the first thumbnail loaded, load the first instance in the mainWidget if (mainWidget_->GetLayerCount() == 0) { - mainWidget_->AddLayer(smartLoader_->GetFrame(instancesIdsPerSeriesId_[seriesId][0], 0)); + smartLoader_->SetFrameInWidget(*mainWidget_, 0, instancesIdsPerSeriesId_[seriesId][0], 0); } } } @@ -362,7 +365,7 @@ thumbnails_.push_back(thumbnailWidget); thumbnailsLayout_->AddWidget(thumbnailWidget); thumbnailWidget->RegisterObserverCallback(new Callable(*this, &SimpleViewerApplication::OnWidgetGeometryChanged)); - thumbnailWidget->AddLayer(smartLoader_->GetFrame(instanceId, 0)); + smartLoader_->SetFrameInWidget(*thumbnailWidget, 0, instanceId, 0); thumbnailWidget->SetInteractor(*thumbnailInteractor_); } @@ -378,10 +381,7 @@ void SelectSeriesInMainViewport(const std::string& seriesId) { - mainWidget_->ReplaceLayer(0, smartLoader_->GetFrame(instancesIdsPerSeriesId_[seriesId][0], 0)); -#if ORTHANC_ENABLE_WASM==1 - NotifyStatusUpdateFromCppToWeb("series-description=" + seriesTags_[seriesId]["MainDicomTags"]["SeriesDescription"].asString()); -#endif + smartLoader_->SetFrameInWidget(*mainWidget_, 0, instancesIdsPerSeriesId_[seriesId][0], 0); } virtual void OnPushButton1Clicked() {} diff -r b66d13708f40 -r 3a4ca166fafa Framework/Layers/ColorFrameRenderer.cpp --- a/Framework/Layers/ColorFrameRenderer.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Layers/ColorFrameRenderer.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -30,7 +30,8 @@ { std::auto_ptr display(new CairoSurface(frame_->GetWidth(), frame_->GetHeight())); - Orthanc::ImageAccessor target = display->GetAccessor(); + Orthanc::ImageAccessor target; + display->GetAccessor(target); Orthanc::ImageProcessing::Convert(target, *frame_); return display.release(); diff -r b66d13708f40 -r 3a4ca166fafa Framework/Layers/GrayscaleFrameRenderer.cpp --- a/Framework/Layers/GrayscaleFrameRenderer.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Layers/GrayscaleFrameRenderer.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -52,7 +52,8 @@ lut = reinterpret_cast(Orthanc::EmbeddedResources::GetFileResourceBuffer(style.lut_)); } - Orthanc::ImageAccessor target = result->GetAccessor(); + Orthanc::ImageAccessor target; + result->GetAccessor(target); const unsigned int width = target.GetWidth(); const unsigned int height = target.GetHeight(); diff -r b66d13708f40 -r 3a4ca166fafa Framework/Layers/ILayerSource.h --- a/Framework/Layers/ILayerSource.h Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Layers/ILayerSource.h Mon Oct 08 17:10:08 2018 +0200 @@ -25,6 +25,8 @@ #include "../Toolbox/Slice.h" #include "../../Framework/Messages/IObservable.h" #include "../../Framework/Messages/IMessage.h" +#include "Core/Images/Image.h" +#include namespace OrthancStone { @@ -46,7 +48,7 @@ } }; - struct LayerReadyMessage : public OriginMessage + struct LayerReadyMessage : public OriginMessage { std::auto_ptr& renderer_; const CoordinateSystem3D& slice_; @@ -64,6 +66,25 @@ { } }; + + struct ImageReadyMessage : public OriginMessage + { + boost::shared_ptr image_; + SliceImageQuality imageQuality_; + const Slice& slice_; + + ImageReadyMessage(ILayerSource& origin, + boost::shared_ptr image, + SliceImageQuality imageQuality, + const Slice& slice + ) + : OriginMessage(origin), + image_(image), + imageQuality_(imageQuality), + slice_(slice) + { + } + }; ILayerSource(MessageBroker& broker) : IObservable(broker) diff -r b66d13708f40 -r 3a4ca166fafa Framework/Layers/LayerSourceBase.cpp --- a/Framework/Layers/LayerSourceBase.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Layers/LayerSourceBase.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -53,4 +53,11 @@ EmitMessage(ILayerSource::LayerReadyMessage(*this, renderer, slice, isError)); } + void LayerSourceBase::NotifyImageReady(boost::shared_ptr image, + SliceImageQuality imageQuality, + const Slice& slice) + { + EmitMessage(ILayerSource::ImageReadyMessage(*this, image, imageQuality, slice)); + } + } diff -r b66d13708f40 -r 3a4ca166fafa Framework/Layers/LayerSourceBase.h --- a/Framework/Layers/LayerSourceBase.h Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Layers/LayerSourceBase.h Mon Oct 08 17:10:08 2018 +0200 @@ -26,6 +26,8 @@ namespace OrthancStone { + class SmartLoader; + class LayerSourceBase : public ILayerSource { protected: @@ -41,15 +43,15 @@ const CoordinateSystem3D& slice, bool isError); + void NotifyImageReady(boost::shared_ptr image, + SliceImageQuality imageQuality, + const Slice& slice); + LayerSourceBase(MessageBroker& broker) : ILayerSource(broker) { -// DeclareEmittableMessage(MessageType_LayerSource_GeometryReady); -// DeclareEmittableMessage(MessageType_LayerSource_GeometryError); -// DeclareEmittableMessage(MessageType_LayerSource_ContentChanged); -// DeclareEmittableMessage(MessageType_LayerSource_SliceChanged); -// DeclareEmittableMessage(MessageType_LayerSource_LayerReady); } + friend class SmartLoader; }; } diff -r b66d13708f40 -r 3a4ca166fafa Framework/Layers/OrthancFrameLayerSource.cpp --- a/Framework/Layers/OrthancFrameLayerSource.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Layers/OrthancFrameLayerSource.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -51,9 +51,17 @@ void OrthancFrameLayerSource::OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message) { + // first notify that the image is ready (targeted to, i.e: an image cache) + LayerSourceBase::NotifyImageReady(message.image_, message.effectiveQuality_, message.slice_); + + // then notify that the layer is ready for render bool isFull = (message.effectiveQuality_ == SliceImageQuality_FullPng || message.effectiveQuality_ == SliceImageQuality_FullPam); - LayerSourceBase::NotifyLayerReady(FrameRenderer::CreateRenderer(message.image_.release(), message.slice_, isFull), + std::auto_ptr accessor(new Orthanc::ImageAccessor()); + message.image_->GetReadOnlyAccessor(*accessor); + + LayerSourceBase::NotifyLayerReady(FrameRenderer::CreateRenderer(accessor.release(), message.slice_, isFull), message.slice_.GetGeometry(), false); + } void OrthancFrameLayerSource::OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message) diff -r b66d13708f40 -r 3a4ca166fafa Framework/Layers/OrthancFrameLayerSource.h --- a/Framework/Layers/OrthancFrameLayerSource.h Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Layers/OrthancFrameLayerSource.h Mon Oct 08 17:10:08 2018 +0200 @@ -55,6 +55,11 @@ quality_ = quality; } + SliceImageQuality GetImageQuality() const + { + return quality_; + } + size_t GetSliceCount() const { return loader_.GetSliceCount(); @@ -75,6 +80,5 @@ void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message); void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message); void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message); -// virtual void HandleMessage(IObservable& from, const IMessage& message); }; } diff -r b66d13708f40 -r 3a4ca166fafa Framework/Messages/MessageType.h --- a/Framework/Messages/MessageType.h Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Messages/MessageType.h Mon Oct 08 17:10:08 2018 +0200 @@ -27,11 +27,12 @@ MessageType_Widget_GeometryChanged, MessageType_Widget_ContentChanged, - MessageType_LayerSource_GeometryReady, + MessageType_LayerSource_GeometryReady, // instance tags have been loaded MessageType_LayerSource_GeometryError, MessageType_LayerSource_ContentChanged, MessageType_LayerSource_SliceChanged, - MessageType_LayerSource_LayerReady, + MessageType_LayerSource_ImageReady, // instance pixels data have been loaded + MessageType_LayerSource_LayerReady, // layer is ready to be rendered MessageType_SliceLoader_GeometryReady, MessageType_SliceLoader_GeometryError, diff -r b66d13708f40 -r 3a4ca166fafa Framework/SmartLoader.cpp --- a/Framework/SmartLoader.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/SmartLoader.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -22,9 +22,69 @@ #include "SmartLoader.h" #include "Layers/OrthancFrameLayerSource.h" #include "Messages/MessageForwarder.h" +#include "Core/Images/Image.h" +#include "Framework/Widgets/LayerWidget.h" +#include "Framework/StoneException.h" +#include "Framework/Layers/FrameRenderer.h" namespace OrthancStone { + enum CachedSliceStatus + { + CachedSliceStatus_Loading, + CachedSliceStatus_Loaded + }; + + class SmartLoader::CachedSlice : public LayerSourceBase + { + public: + unsigned int sliceIndex_; + std::auto_ptr slice_; + boost::shared_ptr image_; + SliceImageQuality effectiveQuality_; + CachedSliceStatus status_; + + public: + + CachedSlice(MessageBroker& broker) + : LayerSourceBase(broker) + {} + + virtual bool GetExtent(std::vector& points, + const CoordinateSystem3D& viewportSlice) + { + // TODO: viewportSlice is not used !!!! + slice_->GetExtent(points); + return true; + } + + virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice) + { + // TODO: viewportSlice is not used !!!! + + // it has already been loaded -> trigger the "layer ready" message immediately + bool isFull = (effectiveQuality_ == SliceImageQuality_FullPng || effectiveQuality_ == SliceImageQuality_FullPam); + std::auto_ptr accessor(new Orthanc::ImageAccessor()); + image_->GetReadOnlyAccessor(*accessor); + LayerSourceBase::NotifyLayerReady(FrameRenderer::CreateRenderer(accessor.release(), *slice_, isFull), + slice_->GetGeometry(), false); + } + + CachedSlice* Clone() const + { + CachedSlice* output = new CachedSlice(broker_); + output->sliceIndex_ = sliceIndex_; + output->slice_.reset(slice_->Clone()); + output->image_ = image_; + output->effectiveQuality_ = effectiveQuality_; + output->status_ = status_; + + return output; + } + + }; + + SmartLoader::SmartLoader(MessageBroker& broker, OrthancApiClient& orthancApiClient) : IObservable(broker), IObserver(broker), @@ -33,7 +93,7 @@ { } - ILayerSource* SmartLoader::GetFrame(const std::string& instanceId, unsigned int frame) + void SmartLoader::SetFrameInWidget(LayerWidget& layerWidget, size_t layerIndex, const std::string& instanceId, unsigned int frame) { // TODO: check if this frame has already been loaded or is already being loaded. // - if already loaded: create a "clone" that will emit the GeometryReady/ImageReady messages "immediately" @@ -41,18 +101,49 @@ // - if currently loading, we need to return an object that will observe the existing LayerSource and forward // the messages to its observables // in both cases, we must be carefull about objects lifecycle !!! - std::auto_ptr layerSource (new OrthancFrameLayerSource(IObserver::broker_, orthancApiClient_)); - layerSource->SetImageQuality(imageQuality_); - layerSource->RegisterObserverCallback(new MessageForwarder(IObserver::broker_, *this)); - layerSource->RegisterObserverCallback(new MessageForwarder(IObserver::broker_, *this)); - layerSource->LoadFrame(instanceId, frame); + + std::auto_ptr layerSource; + + if (cachedSlices_.find(instanceId) != cachedSlices_.end() && cachedSlices_[instanceId]->status_ == CachedSliceStatus_Loaded) + { + layerSource.reset(cachedSlices_[instanceId]->Clone()); + } + else + { + layerSource.reset(new OrthancFrameLayerSource(IObserver::broker_, orthancApiClient_)); + dynamic_cast(layerSource.get())->SetImageQuality(imageQuality_); + layerSource->RegisterObserverCallback(new Callable(*this, &SmartLoader::OnLayerGeometryReady)); + layerSource->RegisterObserverCallback(new Callable(*this, &SmartLoader::OnImageReady)); + layerSource->RegisterObserverCallback(new Callable(*this, &SmartLoader::OnLayerReady)); + dynamic_cast(layerSource.get())->LoadFrame(instanceId, frame); + } - return layerSource.release(); + // make sure that the widget registers the events before we trigger them + if (layerWidget.GetLayerCount() == layerIndex) + { + layerWidget.AddLayer(layerSource.release()); + } + else if (layerWidget.GetLayerCount() > layerIndex) + { + layerWidget.ReplaceLayer(layerIndex, layerSource.release()); + } + else + { + throw StoneException(ErrorCode_CanOnlyAddOneLayerAtATime); + } + + SmartLoader::CachedSlice* cachedSlice = dynamic_cast(layerSource.get()); + if (cachedSlice != NULL) + { + cachedSlice->NotifyGeometryReady(); + } + } + void SmartLoader::LoadStudyList() { -// orthancApiClient_.ScheduleGetJsonRequest("/studies"); + // orthancApiClient_.ScheduleGetJsonRequest("/studies"); } void PreloadStudy(const std::string studyId) @@ -66,4 +157,48 @@ } + void SmartLoader::OnLayerGeometryReady(const ILayerSource::GeometryReadyMessage& message) + { + OrthancFrameLayerSource& source = dynamic_cast(message.origin_); + // save the slice + const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount() + std::string instanceId = slice.GetOrthancInstanceId(); + + CachedSlice* cachedSlice = new CachedSlice(IObserver::broker_); + cachedSlice->slice_.reset(slice.Clone()); + cachedSlice->effectiveQuality_ = source.GetImageQuality(); + cachedSlice->status_ = CachedSliceStatus_Loading; + + cachedSlices_[instanceId] = boost::shared_ptr(cachedSlice); + + // re-emit original Layer message to observers + EmitMessage(message); + } + + void SmartLoader::OnImageReady(const ILayerSource::ImageReadyMessage& message) + { + OrthancFrameLayerSource& source = dynamic_cast(message.origin_); + + // save the slice + const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount() ? + std::string instanceId = slice.GetOrthancInstanceId(); + + boost::shared_ptr cachedSlice(new CachedSlice(IObserver::broker_)); + cachedSlice->image_ = message.image_; + cachedSlice->effectiveQuality_ = message.imageQuality_; + cachedSlice->slice_.reset(message.slice_.Clone()); + cachedSlice->status_ = CachedSliceStatus_Loaded; + + cachedSlices_[instanceId] = cachedSlice; + + // re-emit original Layer message to observers + EmitMessage(message); + } + + void SmartLoader::OnLayerReady(const ILayerSource::LayerReadyMessage& message) + { + // re-emit original Layer message to observers + EmitMessage(message); + } + } diff -r b66d13708f40 -r 3a4ca166fafa Framework/SmartLoader.h --- a/Framework/SmartLoader.h Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/SmartLoader.h Mon Oct 08 17:10:08 2018 +0200 @@ -28,8 +28,16 @@ namespace OrthancStone { - class SmartLoader : public IObservable, IObserver + class LayerWidget; + + class SmartLoader : public IObservable, public IObserver { + struct CachedSlice; + + protected: + typedef std::map> CachedSlices; + CachedSlices cachedSlices_; + SliceImageQuality imageQuality_; OrthancApiClient& orthancApiClient_; @@ -44,10 +52,15 @@ void SetImageQuality(SliceImageQuality imageQuality) { imageQuality_ = imageQuality; } - ILayerSource* GetFrame(const std::string& instanceId, unsigned int frame); + void SetFrameInWidget(LayerWidget& layerWidget, size_t layerIndex, const std::string& instanceId, unsigned int frame); void GetFirstInstanceIdForSeries(std::string& output, const std::string& seriesId); + private: + void OnLayerGeometryReady(const ILayerSource::GeometryReadyMessage& message); + void OnImageReady(const ILayerSource::ImageReadyMessage& message); + void OnLayerReady(const ILayerSource::LayerReadyMessage& message); + }; } diff -r b66d13708f40 -r 3a4ca166fafa Framework/StoneException.h --- a/Framework/StoneException.h Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/StoneException.h Mon Oct 08 17:10:08 2018 +0200 @@ -36,6 +36,7 @@ ErrorCode_PromiseSingleSuccessHandler, // a Promise can only have a single success handler ErrorCode_PromiseSingleFailureHandler, // a Promise can only have a single failure handler + ErrorCode_CanOnlyAddOneLayerAtATime, ErrorCode_CommandJsonInvalidFormat, ErrorCode_Last }; diff -r b66d13708f40 -r 3a4ca166fafa Framework/Toolbox/OrthancSlicesLoader.cpp --- a/Framework/Toolbox/OrthancSlicesLoader.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Toolbox/OrthancSlicesLoader.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -173,7 +173,7 @@ }; void OrthancSlicesLoader::NotifySliceImageSuccess(const Operation& operation, - std::auto_ptr& image) + boost::shared_ptr image) { if (image.get() == NULL) { @@ -341,7 +341,7 @@ void OrthancSlicesLoader::ParseSliceImagePng(const OrthancApiClient::BinaryResponseReadyMessage& message) { const Operation& operation = dynamic_cast(*message.Payload); - std::auto_ptr image; + boost::shared_ptr image; try { @@ -381,7 +381,7 @@ void OrthancSlicesLoader::ParseSliceImagePam(const OrthancApiClient::BinaryResponseReadyMessage& message) { const Operation& operation = dynamic_cast(*message.Payload); - std::auto_ptr image; + boost::shared_ptr image; try { @@ -461,7 +461,7 @@ } } - std::auto_ptr reader; + boost::shared_ptr reader; { std::string jpeg; @@ -548,11 +548,11 @@ } // Decode a grayscale JPEG 8bpp image coming from the Web viewer - std::auto_ptr image + boost::shared_ptr image (new Orthanc::Image(expectedFormat, reader->GetWidth(), reader->GetHeight(), false)); Orthanc::ImageProcessing::Convert(*image, *reader); - reader.reset(NULL); + reader = NULL; float scaling = static_cast(stretchHigh - stretchLow) / 255.0f; @@ -567,8 +567,7 @@ class StringImage : - public Orthanc::ImageAccessor, - public boost::noncopyable + public Orthanc::ImageAccessor { private: std::string buffer_; @@ -613,7 +612,7 @@ { // This is the case of RT-DOSE (uint32_t values) - std::auto_ptr image + boost::shared_ptr image (new StringImage(Orthanc::PixelFormat_Grayscale32, info.GetWidth(), info.GetHeight(), raw)); @@ -637,7 +636,7 @@ info.GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome2 && raw.size() == info.GetWidth() * info.GetHeight() * 2) { - std::auto_ptr image + boost::shared_ptr image (new StringImage(Orthanc::PixelFormat_Grayscale16, info.GetWidth(), info.GetHeight(), raw)); diff -r b66d13708f40 -r 3a4ca166fafa Framework/Toolbox/OrthancSlicesLoader.h --- a/Framework/Toolbox/OrthancSlicesLoader.h Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Toolbox/OrthancSlicesLoader.h Mon Oct 08 17:10:08 2018 +0200 @@ -13,7 +13,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **/ @@ -27,6 +27,8 @@ #include "../Messages/IObservable.h" #include #include "OrthancApiClient.h" +#include "Core/Images/Image.h" + namespace OrthancStone { @@ -41,13 +43,13 @@ { unsigned int sliceIndex_; const Slice& slice_; - std::auto_ptr& image_; + boost::shared_ptr image_; SliceImageQuality effectiveQuality_; SliceImageReadyMessage(unsigned int sliceIndex, - const Slice& slice, - std::auto_ptr& image, - SliceImageQuality effectiveQuality) + const Slice& slice, + boost::shared_ptr image, + SliceImageQuality effectiveQuality) : BaseMessage(), sliceIndex_(sliceIndex), slice_(slice), @@ -64,8 +66,8 @@ SliceImageQuality effectiveQuality_; SliceImageErrorMessage(unsigned int sliceIndex, - const Slice& slice, - SliceImageQuality effectiveQuality) + const Slice& slice, + SliceImageQuality effectiveQuality) : BaseMessage(), slice_(slice), sliceIndex_(sliceIndex), @@ -100,8 +102,8 @@ SlicesSorter slices_; void NotifySliceImageSuccess(const Operation& operation, - std::auto_ptr& image); - + boost::shared_ptr image); + void NotifySliceImageError(const Operation& operation); void OnGeometryError(const OrthancApiClient::HttpErrorMessage& message); diff -r b66d13708f40 -r 3a4ca166fafa Framework/Toolbox/Slice.cpp --- a/Framework/Toolbox/Slice.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Toolbox/Slice.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -45,6 +45,28 @@ return false; } } + + Slice* Slice::Clone() const + { + std::auto_ptr target(new Slice()); + + target->type_ = type_; + target->orthancInstanceId_ = orthancInstanceId_; + target->sopClassUid_ = sopClassUid_; + target->frame_ = frame_; + target->frameCount_ = frameCount_; + target->geometry_ = geometry_; + target->pixelSpacingX_ = pixelSpacingX_; + target->pixelSpacingY_ = pixelSpacingY_; + target->thickness_ = thickness_; + target->width_ = width_; + target->height_ = height_; + target->converter_ = converter_; + if (imageInformation_.get() != NULL) + target->imageInformation_.reset(imageInformation_->Clone()); + + return target.release(); + } bool Slice::ComputeRTDoseGeometry(const Orthanc::DicomMap& dataset, unsigned int frame) diff -r b66d13708f40 -r 3a4ca166fafa Framework/Toolbox/Slice.h --- a/Framework/Toolbox/Slice.h Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Toolbox/Slice.h Mon Oct 08 17:10:08 2018 +0200 @@ -136,5 +136,7 @@ void GetExtent(std::vector& points) const; const Orthanc::DicomImageInformation& GetImageInformation() const; + + Slice* Clone() const; }; } diff -r b66d13708f40 -r 3a4ca166fafa Framework/Viewport/CairoSurface.cpp --- a/Framework/Viewport/CairoSurface.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Viewport/CairoSurface.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -105,24 +105,23 @@ void CairoSurface::Copy(const CairoSurface& other) { - Orthanc::ImageAccessor source = other.GetConstAccessor(); - Orthanc::ImageAccessor target = GetAccessor(); + Orthanc::ImageAccessor source, target; + + other.GetConstAccessor(source); + GetAccessor(target); + Orthanc::ImageProcessing::Copy(target, source); } - Orthanc::ImageAccessor CairoSurface::GetConstAccessor() const + void CairoSurface::GetConstAccessor(Orthanc::ImageAccessor& target) const { - Orthanc::ImageAccessor accessor; - accessor.AssignReadOnly(Orthanc::PixelFormat_BGRA32, width_, height_, pitch_, buffer_); - return accessor; + target.AssignReadOnly(Orthanc::PixelFormat_BGRA32, width_, height_, pitch_, buffer_); } - Orthanc::ImageAccessor CairoSurface::GetAccessor() + void CairoSurface::GetAccessor(Orthanc::ImageAccessor& target) { - Orthanc::ImageAccessor accessor; - accessor.AssignWritable(Orthanc::PixelFormat_BGRA32, width_, height_, pitch_, buffer_); - return accessor; + target.AssignWritable(Orthanc::PixelFormat_BGRA32, width_, height_, pitch_, buffer_); } } diff -r b66d13708f40 -r 3a4ca166fafa Framework/Viewport/CairoSurface.h --- a/Framework/Viewport/CairoSurface.h Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Viewport/CairoSurface.h Mon Oct 08 17:10:08 2018 +0200 @@ -98,8 +98,8 @@ return surface_; } - Orthanc::ImageAccessor GetConstAccessor() const; + void GetConstAccessor(Orthanc::ImageAccessor& target) const; - Orthanc::ImageAccessor GetAccessor(); + void GetAccessor(Orthanc::ImageAccessor& target); }; } diff -r b66d13708f40 -r 3a4ca166fafa Framework/Viewport/WidgetViewport.cpp --- a/Framework/Viewport/WidgetViewport.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Viewport/WidgetViewport.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -108,7 +108,8 @@ return false; } - Orthanc::ImageAccessor background = background_.GetAccessor(); + Orthanc::ImageAccessor background; + background_.GetAccessor(background); if (backgroundChanged_ && !centralWidget_->Render(background)) diff -r b66d13708f40 -r 3a4ca166fafa Framework/Volumes/ImageBuffer3D.cpp --- a/Framework/Volumes/ImageBuffer3D.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Volumes/ImageBuffer3D.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -13,7 +13,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **/ @@ -29,53 +29,47 @@ namespace OrthancStone { - Orthanc::ImageAccessor ImageBuffer3D::GetAxialSliceAccessor(unsigned int slice, - bool readOnly) const + void ImageBuffer3D::GetAxialSliceAccessor(Orthanc::ImageAccessor& target, + unsigned int slice, + bool readOnly) const { if (slice >= depth_) { throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - Orthanc::ImageAccessor accessor; - if (readOnly) { - accessor.AssignReadOnly(format_, width_, height_, image_.GetPitch(), - image_.GetConstRow(height_ * (depth_ - 1 - slice))); + target.AssignReadOnly(format_, width_, height_, image_.GetPitch(), + image_.GetConstRow(height_ * (depth_ - 1 - slice))); } else { - accessor.AssignWritable(format_, width_, height_, image_.GetPitch(), - image_.GetRow(height_ * (depth_ - 1 - slice))); + target.AssignWritable(format_, width_, height_, image_.GetPitch(), + image_.GetRow(height_ * (depth_ - 1 - slice))); } - - return accessor; } - Orthanc::ImageAccessor ImageBuffer3D::GetCoronalSliceAccessor(unsigned int slice, - bool readOnly) const + void ImageBuffer3D::GetCoronalSliceAccessor(Orthanc::ImageAccessor& target, + unsigned int slice, + bool readOnly) const { if (slice >= height_) { throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - Orthanc::ImageAccessor accessor; - if (readOnly) { - accessor.AssignReadOnly(format_, width_, depth_, image_.GetPitch() * height_, - image_.GetConstRow(slice)); + target.AssignReadOnly(format_, width_, depth_, image_.GetPitch() * height_, + image_.GetConstRow(slice)); } else { - accessor.AssignWritable(format_, width_, depth_, image_.GetPitch() * height_, - image_.GetRow(slice)); + target.AssignWritable(format_, width_, depth_, image_.GetPitch() * height_, + image_.GetRow(slice)); } - - return accessor; } @@ -97,7 +91,7 @@ for (unsigned int y = 0; y < height_; y++) { - const void* source = (reinterpret_cast(image_.GetConstRow(y + z * height_)) + + const void* source = (reinterpret_cast(image_.GetConstRow(y + z * height_)) + bytesPerPixel * slice); memcpy(target, source, bytesPerPixel); @@ -163,20 +157,20 @@ Vector result; switch (projection) { - case VolumeProjection_Axial: - result = voxelDimensions_; - break; + case VolumeProjection_Axial: + result = voxelDimensions_; + break; - case VolumeProjection_Coronal: - LinearAlgebra::AssignVector(result, voxelDimensions_[0], voxelDimensions_[2], voxelDimensions_[1]); - break; + case VolumeProjection_Coronal: + LinearAlgebra::AssignVector(result, voxelDimensions_[0], voxelDimensions_[2], voxelDimensions_[1]); + break; - case VolumeProjection_Sagittal: - LinearAlgebra::AssignVector(result, voxelDimensions_[1], voxelDimensions_[2], voxelDimensions_[0]); - break; + case VolumeProjection_Sagittal: + LinearAlgebra::AssignVector(result, voxelDimensions_[1], voxelDimensions_[2], voxelDimensions_[0]); + break; - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } return result; @@ -189,23 +183,23 @@ { switch (projection) { - case VolumeProjection_Axial: - width = width_; - height = height_; - break; + case VolumeProjection_Axial: + width = width_; + height = height_; + break; - case VolumeProjection_Coronal: - width = width_; - height = depth_; - break; + case VolumeProjection_Coronal: + width = width_; + height = depth_; + break; - case VolumeProjection_Sagittal: - width = height_; - height = depth_; - break; + case VolumeProjection_Sagittal: + width = height_; + height = depth_; + break; - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } } @@ -216,51 +210,51 @@ switch (projection) { - case VolumeProjection_Axial: - for (unsigned int z = 0; z < depth_; z++) - { - Vector origin = axialGeometry_.GetOrigin(); - origin += static_cast(z) * voxelDimensions_[2] * axialGeometry_.GetNormal(); + case VolumeProjection_Axial: + for (unsigned int z = 0; z < depth_; z++) + { + Vector origin = axialGeometry_.GetOrigin(); + origin += static_cast(z) * voxelDimensions_[2] * axialGeometry_.GetNormal(); - result->AddSlice(origin, - axialGeometry_.GetAxisX(), - axialGeometry_.GetAxisY()); - } - break; + result->AddSlice(origin, + axialGeometry_.GetAxisX(), + axialGeometry_.GetAxisY()); + } + break; - case VolumeProjection_Coronal: - for (unsigned int y = 0; y < height_; y++) - { - Vector origin = axialGeometry_.GetOrigin(); - origin += static_cast(y) * voxelDimensions_[1] * axialGeometry_.GetAxisY(); - origin += static_cast(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal(); + case VolumeProjection_Coronal: + for (unsigned int y = 0; y < height_; y++) + { + Vector origin = axialGeometry_.GetOrigin(); + origin += static_cast(y) * voxelDimensions_[1] * axialGeometry_.GetAxisY(); + origin += static_cast(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal(); - result->AddSlice(origin, - axialGeometry_.GetAxisX(), - -axialGeometry_.GetNormal()); - } - break; + result->AddSlice(origin, + axialGeometry_.GetAxisX(), + -axialGeometry_.GetNormal()); + } + break; - case VolumeProjection_Sagittal: - for (unsigned int x = 0; x < width_; x++) - { - Vector origin = axialGeometry_.GetOrigin(); - origin += static_cast(x) * voxelDimensions_[0] * axialGeometry_.GetAxisX(); - origin += static_cast(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal(); + case VolumeProjection_Sagittal: + for (unsigned int x = 0; x < width_; x++) + { + Vector origin = axialGeometry_.GetOrigin(); + origin += static_cast(x) * voxelDimensions_[0] * axialGeometry_.GetAxisX(); + origin += static_cast(depth_ - 1) * voxelDimensions_[2] * axialGeometry_.GetNormal(); - result->AddSlice(origin, - axialGeometry_.GetAxisY(), - -axialGeometry_.GetNormal()); - } - break; + result->AddSlice(origin, + axialGeometry_.GetAxisY(), + -axialGeometry_.GetNormal()); + } + break; - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } return result.release(); } - + uint64_t ImageBuffer3D::GetEstimatedMemorySize() const { @@ -278,27 +272,27 @@ } float sliceMin, sliceMax; - + switch (slice.GetFormat()) { - case Orthanc::PixelFormat_Grayscale8: - case Orthanc::PixelFormat_Grayscale16: - case Orthanc::PixelFormat_Grayscale32: - case Orthanc::PixelFormat_SignedGrayscale16: - { - int64_t a, b; - Orthanc::ImageProcessing::GetMinMaxIntegerValue(a, b, slice); - sliceMin = static_cast(a); - sliceMax = static_cast(b); - break; - } + case Orthanc::PixelFormat_Grayscale8: + case Orthanc::PixelFormat_Grayscale16: + case Orthanc::PixelFormat_Grayscale32: + case Orthanc::PixelFormat_SignedGrayscale16: + { + int64_t a, b; + Orthanc::ImageProcessing::GetMinMaxIntegerValue(a, b, slice); + sliceMin = static_cast(a); + sliceMax = static_cast(b); + break; + } - case Orthanc::PixelFormat_Float32: - Orthanc::ImageProcessing::GetMinMaxFloatValue(sliceMin, sliceMax, slice); - break; + case Orthanc::PixelFormat_Float32: + Orthanc::ImageProcessing::GetMinMaxFloatValue(sliceMin, sliceMax, slice); + break; - default: - return; + default: + return; } if (hasRange_) @@ -359,21 +353,21 @@ { switch (projection) { - case VolumeProjection_Axial: - accessor_ = that.GetAxialSliceAccessor(slice, true); - break; + case VolumeProjection_Axial: + that.GetAxialSliceAccessor(accessor_, slice, true); + break; - case VolumeProjection_Coronal: - accessor_ = that.GetCoronalSliceAccessor(slice, true); - break; + case VolumeProjection_Coronal: + that.GetCoronalSliceAccessor(accessor_, slice, true); + break; - case VolumeProjection_Sagittal: - sagittal_.reset(that.ExtractSagittalSlice(slice)); - accessor_ = *sagittal_; - break; + case VolumeProjection_Sagittal: + sagittal_.reset(that.ExtractSagittalSlice(slice)); + sagittal_->GetReadOnlyAccessor(accessor_); + break; - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } } @@ -385,7 +379,7 @@ if (sagittal_.get() != NULL) { // TODO - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); } // Update the dynamic range of the underlying image, if @@ -403,21 +397,21 @@ { switch (projection) { - case VolumeProjection_Axial: - accessor_ = that.GetAxialSliceAccessor(slice, false); - break; + case VolumeProjection_Axial: + that.GetAxialSliceAccessor(accessor_, slice, false); + break; - case VolumeProjection_Coronal: - accessor_ = that.GetCoronalSliceAccessor(slice, false); - break; + case VolumeProjection_Coronal: + that.GetCoronalSliceAccessor(accessor_, slice, false); + break; - case VolumeProjection_Sagittal: - sagittal_.reset(that.ExtractSagittalSlice(slice)); - accessor_ = *sagittal_; - break; + case VolumeProjection_Sagittal: + sagittal_.reset(that.ExtractSagittalSlice(slice)); + sagittal_->GetWriteableAccessor(accessor_); + break; - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } } @@ -473,11 +467,11 @@ const CoordinateSystem3D& axial = GetAxialGeometry(); Vector origin = (axial.MapSliceToWorldCoordinates(-0.5 * ps[0], -0.5 * ps[1]) - - 0.5 * ps[2] * axial.GetNormal()); + 0.5 * ps[2] * axial.GetNormal()); return (origin + axial.GetAxisX() * ps[0] * x * static_cast(GetWidth()) + - axial.GetAxisY() * ps[1] * y * static_cast(GetHeight()) + - axial.GetNormal() * ps[2] * z * static_cast(GetDepth())); + axial.GetAxisY() * ps[1] * y * static_cast(GetHeight()) + + axial.GetNormal() * ps[2] * z * static_cast(GetDepth())); } } diff -r b66d13708f40 -r 3a4ca166fafa Framework/Volumes/ImageBuffer3D.h --- a/Framework/Volumes/ImageBuffer3D.h Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Volumes/ImageBuffer3D.h Mon Oct 08 17:10:08 2018 +0200 @@ -13,7 +13,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **/ @@ -48,11 +48,13 @@ void ExtendImageRange(const Orthanc::ImageAccessor& slice); - Orthanc::ImageAccessor GetAxialSliceAccessor(unsigned int slice, - bool readOnly) const; + void GetAxialSliceAccessor(Orthanc::ImageAccessor& target, + unsigned int slice, + bool readOnly) const; - Orthanc::ImageAccessor GetCoronalSliceAccessor(unsigned int slice, - bool readOnly) const; + void GetCoronalSliceAccessor(Orthanc::ImageAccessor& target, + unsigned int slice, + bool readOnly) const; Orthanc::Image* ExtractSagittalSlice(unsigned int slice) const; diff -r b66d13708f40 -r 3a4ca166fafa Framework/Widgets/CairoWidget.cpp --- a/Framework/Widgets/CairoWidget.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Widgets/CairoWidget.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -63,7 +63,9 @@ if (RenderCairo(context)) { - Orthanc::ImageProcessing::Copy(target, surface_.GetAccessor()); + Orthanc::ImageAccessor source; + surface_.GetAccessor(source); + Orthanc::ImageProcessing::Copy(target, source); return true; } else @@ -86,7 +88,8 @@ } else { - Orthanc::ImageAccessor accessor = surface_.GetAccessor(); + Orthanc::ImageAccessor accessor; + surface_.GetAccessor(accessor); Orthanc::ImageProcessing::Copy(accessor, target); CairoContext context(surface_); diff -r b66d13708f40 -r 3a4ca166fafa Framework/Widgets/LayerWidget.cpp --- a/Framework/Widgets/LayerWidget.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Widgets/LayerWidget.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -23,6 +23,7 @@ #include "../Layers/SliceOutlineRenderer.h" #include "../Toolbox/GeometryToolbox.h" +#include "Framework/Layers/FrameRenderer.h" #include @@ -589,7 +590,7 @@ { LOG(INFO) << "Renderer ready for layer " << index; } - + if (message.renderer_.get() != NULL) { UpdateLayer(index, message.renderer_.release(), message.slice_); diff -r b66d13708f40 -r 3a4ca166fafa Framework/Widgets/LayoutWidget.cpp --- a/Framework/Widgets/LayoutWidget.cpp Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/Widgets/LayoutWidget.cpp Mon Oct 08 17:10:08 2018 +0200 @@ -57,7 +57,8 @@ virtual void Render(Orthanc::ImageAccessor& surface) { - Orthanc::ImageAccessor accessor = surface.GetRegion(left_, top_, width_, height_); + Orthanc::ImageAccessor accessor; + surface.GetRegion(accessor, left_, top_, width_, height_); tracker_->Render(accessor); } @@ -140,7 +141,8 @@ } else { - Orthanc::ImageAccessor accessor = target.GetRegion(left_, top_, width_, height_); + Orthanc::ImageAccessor accessor; + target.GetRegion(accessor, left_, top_, width_, height_); return widget_->Render(accessor); } } @@ -171,7 +173,8 @@ { if (Contains(x, y)) { - Orthanc::ImageAccessor accessor = target.GetRegion(left_, top_, width_, height_); + Orthanc::ImageAccessor accessor; + target.GetRegion(accessor, left_, top_, width_, height_); widget_->RenderMouseOver(accessor, x - left_, y - top_); } diff -r b66d13708f40 -r 3a4ca166fafa Framework/dev.h --- a/Framework/dev.h Fri Oct 05 11:57:36 2018 +0200 +++ b/Framework/dev.h Mon Oct 08 17:10:08 2018 +0200 @@ -13,7 +13,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **/ @@ -41,10 +41,10 @@ namespace OrthancStone { // TODO: Handle errors while loading - class OrthancVolumeImage : - public SlicedVolumeBase, - public OrthancStone::IObserver - { + class OrthancVolumeImage : + public SlicedVolumeBase, + public OrthancStone::IObserver + { private: OrthancSlicesLoader loader_; std::auto_ptr image_; @@ -64,7 +64,7 @@ } - static bool IsCompatible(const Slice& a, + static bool IsCompatible(const Slice& a, const Slice& b) { if (!GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(), @@ -98,10 +98,10 @@ } - static double GetDistance(const Slice& a, + static double GetDistance(const Slice& a, const Slice& b) { - return fabs(a.GetGeometry().ProjectAlongNormal(a.GetGeometry().GetOrigin()) - + return fabs(a.GetGeometry().ProjectAlongNormal(a.GetGeometry().GetOrigin()) - a.GetGeometry().ProjectAlongNormal(b.GetGeometry().GetOrigin())); } @@ -174,10 +174,10 @@ } virtual void OnSliceImageReady(const OrthancSlicesLoader& loader, - unsigned int sliceIndex, - const Slice& slice, - std::auto_ptr& image, - SliceImageQuality quality) + unsigned int sliceIndex, + const Slice& slice, + const boost::shared_ptr& image, + SliceImageQuality quality) { { ImageBuffer3D::SliceWriter writer(*image_, VolumeProjection_Axial, sliceIndex); @@ -221,9 +221,9 @@ }; break; case MessageType_SliceLoader_ImageError: { - const OrthancSlicesLoader::SliceImageErrorMessage& msg = dynamic_cast(message); - LOG(ERROR) << "Cannot download slice " << msg.sliceIndex_ << " in a volume image"; - ScheduleSliceDownload(); + const OrthancSlicesLoader::SliceImageErrorMessage& msg = dynamic_cast(message); + LOG(ERROR) << "Cannot download slice " << msg.sliceIndex_ << " in a volume image"; + ScheduleSliceDownload(); }; break; default: VLOG("unhandled message type" << message.GetType()); @@ -233,13 +233,13 @@ public: OrthancVolumeImage(MessageBroker& broker, OrthancApiClient& orthanc, - bool computeRange) : + bool computeRange) : OrthancStone::IObserver(broker), loader_(broker, orthanc), computeRange_(computeRange), pendingSlices_(0) { - // TODO: replace with new callables loader_.RegisterObserver(*this); + // TODO: replace with new callables loader_.RegisterObserver(*this); } void ScheduleLoadSeries(const std::string& seriesId) @@ -371,7 +371,7 @@ axialThickness * axial.GetGeometry().GetNormal()); reference_ = CoordinateSystem3D(origin, - axial.GetGeometry().GetAxisX(), + axial.GetGeometry().GetAxisX(), -axial.GetGeometry().GetNormal()); } @@ -393,7 +393,7 @@ axialThickness * axial.GetGeometry().GetNormal()); reference_ = CoordinateSystem3D(origin, - axial.GetGeometry().GetAxisY(), + axial.GetGeometry().GetAxisY(), axial.GetGeometry().GetNormal()); } @@ -410,20 +410,20 @@ switch (projection) { - case VolumeProjection_Axial: - SetupAxial(volume); - break; + case VolumeProjection_Axial: + SetupAxial(volume); + break; - case VolumeProjection_Coronal: - SetupCoronal(volume); - break; + case VolumeProjection_Coronal: + SetupCoronal(volume); + break; - case VolumeProjection_Sagittal: - SetupSagittal(volume); - break; + case VolumeProjection_Sagittal: + SetupSagittal(volume); + break; - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } } @@ -487,8 +487,8 @@ class VolumeImageSource : - public LayerSourceBase, - private ISlicedVolume::IObserver + public LayerSourceBase, + private ISlicedVolume::IObserver { private: OrthancVolumeImage& volume_; @@ -512,12 +512,12 @@ LayerSourceBase::NotifyGeometryReady(); } - + virtual void NotifyGeometryError(const ISlicedVolume& volume) { LayerSourceBase::NotifyGeometryError(); } - + virtual void NotifyContentChange(const ISlicedVolume& volume) { LayerSourceBase::NotifyContentChange(); @@ -546,17 +546,17 @@ switch (projection) { - case VolumeProjection_Axial: - return *axialGeometry_; + case VolumeProjection_Axial: + return *axialGeometry_; - case VolumeProjection_Sagittal: - return *sagittalGeometry_; + case VolumeProjection_Sagittal: + return *sagittalGeometry_; - case VolumeProjection_Coronal: - return *coronalGeometry_; + case VolumeProjection_Coronal: + return *coronalGeometry_; - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } } @@ -613,7 +613,7 @@ return false; } else - { + { // As the slices of the volumic image are arranged in a box, // we only consider one single reference slice (the one with index 0). std::auto_ptr slice(GetProjectionGeometry(projection).GetSlice(0)); @@ -650,9 +650,9 @@ std::auto_ptr slice(geometry.GetSlice(closest)); LayerSourceBase::NotifyLayerReady( - FrameRenderer::CreateRenderer(frame.release(), *slice, isFullQuality), - //new SliceOutlineRenderer(slice), - slice->GetGeometry(), false); + FrameRenderer::CreateRenderer(frame.release(), *slice, isFullQuality), + //new SliceOutlineRenderer(slice), + slice->GetGeometry(), false); return; } } @@ -665,8 +665,8 @@ class VolumeImageInteractor : - public IWorldSceneInteractor, - protected ISlicedVolume::IObserver + public IWorldSceneInteractor, + protected ISlicedVolume::IObserver { private: LayerWidget& widget_; @@ -687,11 +687,11 @@ widget_.SetDefaultView(); } } - + virtual void NotifyGeometryError(const ISlicedVolume& volume) { } - + virtual void NotifyContentChange(const ISlicedVolume& volume) { } @@ -731,19 +731,19 @@ IStatusBar* statusBar) { int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1); - + switch (direction) { - case MouseWheelDirection_Up: - OffsetSlice(-scale); - break; + case MouseWheelDirection_Up: + OffsetSlice(-scale); + break; - case MouseWheelDirection_Down: - OffsetSlice(scale); - break; + case MouseWheelDirection_Down: + OffsetSlice(scale); + break; - default: - break; + default: + break; } } @@ -754,15 +754,15 @@ { switch (key) { - case 's': - widget.SetDefaultView(); - break; + case 's': + widget.SetDefaultView(); + break; - default: - break; + default: + break; } } - + public: VolumeImageInteractor(OrthancVolumeImage& volume, LayerWidget& widget, @@ -807,13 +807,13 @@ slice = slices_->GetSliceCount() - 1; } - if (slice != static_cast(slice_)) + if (slice != static_cast(slice_)) { SetSlice(slice); - } + } } } - + void SetSlice(size_t slice) { if (slices_.get() != NULL) @@ -856,7 +856,7 @@ const CoordinateSystem3D& slice = otherPlane_.GetSlice(); // Compute the line of intersection between the two slices - if (!GeometryToolbox::IntersectTwoPlanes(p, d, + if (!GeometryToolbox::IntersectTwoPlanes(p, d, slice.GetOrigin(), slice.GetNormal(), viewportSlice.GetOrigin(), viewportSlice.GetNormal())) { @@ -871,7 +871,7 @@ const Extent2D extent = otherPlane_.GetSceneExtent(); - if (GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2, + if (GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2, x1, y1, x2, y2, extent.GetX1(), extent.GetY1(), extent.GetX2(), extent.GetY2())) @@ -884,6 +884,6 @@ NotifyLayerReady(NULL, reference.GetGeometry(), false); } } - } + } }; }