# HG changeset patch # User Sebastien Jodogne # Date 1497445627 -7200 # Node ID 71d574a3607fb272dd225dfcc3885a88ac62dc87 # Parent 6a7c702a7531a4a39b094ca8aa631f02451903ba removing unused files diff -r 6a7c702a7531 -r 71d574a3607f Applications/BasicApplicationContext.cpp --- a/Applications/BasicApplicationContext.cpp Wed Jun 14 14:21:24 2017 +0200 +++ b/Applications/BasicApplicationContext.cpp Wed Jun 14 15:07:07 2017 +0200 @@ -22,8 +22,6 @@ #include "BasicApplicationContext.h" #include "../../Framework/Toolbox/OrthancSeriesLoader.h" -#include "../../Framework/Volumes/VolumeImageSimplePolicy.h" -#include "../../Framework/Volumes/VolumeImageProgressivePolicy.h" namespace OrthancStone { diff -r 6a7c702a7531 -r 71d574a3607f Framework/Layers/ILayerRendererFactory.h --- a/Framework/Layers/ILayerRendererFactory.h Wed Jun 14 14:21:24 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * 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 . - **/ - - -#pragma once - -#include "ILayerRenderer.h" -#include "../Toolbox/SliceGeometry.h" -#include "../Volumes/ISliceableVolume.h" - -namespace OrthancStone -{ - class ILayerRendererFactory : public boost::noncopyable - { - public: - virtual ~ILayerRendererFactory() - { - } - - virtual bool GetExtent(double& x1, - double& y1, - double& x2, - double& y2, - const SliceGeometry& displaySlice) = 0; - - // This operation can be slow, as it might imply the download of a - // slice from Orthanc. The result might be NULL, if the slice is - // not compatible with the underlying source volume. - virtual ILayerRenderer* CreateLayerRenderer(const SliceGeometry& displaySlice) = 0; - - virtual bool HasSourceVolume() const = 0; - - virtual ISliceableVolume& GetSourceVolume() const = 0; - }; -} diff -r 6a7c702a7531 -r 71d574a3607f Framework/Volumes/VolumeImage.cpp --- a/Framework/Volumes/VolumeImage.cpp Wed Jun 14 14:21:24 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,400 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * 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 . - **/ - - -#include "VolumeImage.h" - -#include "../../Resources/Orthanc/Core/Logging.h" -#include "../Layers/FrameRenderer.h" - -namespace OrthancStone -{ - void VolumeImage::StoreUpdateTime() - { - lastUpdate_ = MessagingToolbox::Timestamp(); - } - - - void VolumeImage::NotifyChange(bool force) - { - bool go = false; - - if (force) - { - go = true; - } - else - { - // Don't notify the observers more than 5 times per second - MessagingToolbox::Timestamp now; - go = (now.GetMillisecondsSince(lastUpdate_) > 200); - } - - if (go) - { - StoreUpdateTime(); - observers_.NotifyChange(this); - } - } - - - void VolumeImage::LoadThread(VolumeImage* that) - { - while (that->continue_) - { - bool complete = false; - bool done = that->policy_->DownloadStep(complete); - - if (complete) - { - that->loadingComplete_ = true; - } - - if (done) - { - break; - } - else - { - that->NotifyChange(false); - } - } - - that->NotifyChange(true); - } - - - VolumeImage::VolumeImage(ISeriesLoader* loader) : // Takes ownership - loader_(loader), - threads_(1), - started_(false), - continue_(false), - loadingComplete_(false) - { - if (loader == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - const size_t depth = loader_->GetGeometry().GetSliceCount(); - - if (depth < 2) - { - // Empty or flat series - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - - // TODO Check pixel spacing, slice thickness, and windowing are - // constant across slices - referenceDataset_.reset(loader->DownloadDicom(0)); - - double spacingZ; - - { - // Project the origin of the first and last slices onto the normal - const SliceGeometry& s1 = loader_->GetGeometry().GetSlice(0); - const SliceGeometry& s2 = loader_->GetGeometry().GetSlice(depth - 1); - const Vector& normal = loader_->GetGeometry().GetNormal(); - - double p1 = boost::numeric::ublas::inner_prod(s1.GetOrigin(), normal); - double p2 = boost::numeric::ublas::inner_prod(s2.GetOrigin(), normal); - - spacingZ = fabs(p2 - p1) / static_cast(depth); - - // TODO Check that all slices are evenly distributed - } - - buffer_.reset(new ImageBuffer3D(loader_->GetPixelFormat(), - loader_->GetWidth(), - loader_->GetHeight(), - depth)); - buffer_->Clear(); - buffer_->SetAxialGeometry(loader_->GetGeometry().GetSlice(0)); - - double spacingX, spacingY; - GeometryToolbox::GetPixelSpacing(spacingX, spacingY, *referenceDataset_); - buffer_->SetVoxelDimensions(spacingX, spacingY, spacingZ); - - // These 3 values are only used to speed up the LayerFactory - axialGeometry_.reset(buffer_->GetGeometry(VolumeProjection_Axial)); - coronalGeometry_.reset(buffer_->GetGeometry(VolumeProjection_Coronal)); - sagittalGeometry_.reset(buffer_->GetGeometry(VolumeProjection_Sagittal)); - } - - - VolumeImage::~VolumeImage() - { - Stop(); - - for (size_t i = 0; i < threads_.size(); i++) - { - if (threads_[i] != NULL) - { - delete threads_[i]; - } - } - } - - - void VolumeImage::SetDownloadPolicy(IDownloadPolicy* policy) // Takes ownership - { - if (started_) - { - LOG(ERROR) << "Cannot change the number of threads after a call to Start()"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - policy_.reset(policy); - } - - - void VolumeImage::SetThreadCount(size_t count) - { - if (started_) - { - LOG(ERROR) << "Cannot change the number of threads after a call to Start()"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - if (count <= 0) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - threads_.resize(count); - } - - - void VolumeImage::Register(IObserver& observer) - { - observers_.Register(observer); - } - - - void VolumeImage::Unregister(IObserver& observer) - { - observers_.Unregister(observer); - } - - - void VolumeImage::Start() - { - if (started_) - { - LOG(ERROR) << "Cannot call Start() twice"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - started_ = true; - StoreUpdateTime(); - - if (policy_.get() != NULL && - threads_.size() > 0) - { - continue_ = true; - policy_->Initialize(*buffer_, *loader_); - - for (size_t i = 0; i < threads_.size(); i++) - { - assert(threads_[i] == NULL); - threads_[i] = new boost::thread(LoadThread, this); - } - } - } - - - void VolumeImage::Stop() - { - if (!started_) - { - LOG(ERROR) << "Cannot call Stop() without calling Start() beforehand"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - if (continue_) - { - continue_ = false; - - for (size_t i = 0; i < threads_.size(); i++) - { - if (threads_[i]->joinable()) - { - threads_[i]->join(); - } - } - - assert(policy_.get() != NULL); - policy_->Finalize(); - } - } - - - ParallelSlices* VolumeImage::GetGeometry(VolumeProjection projection, - bool reverse) - { - std::auto_ptr slices(buffer_->GetGeometry(projection)); - - if (reverse) - { - return slices->Reverse(); - } - else - { - return slices.release(); - } - } - - - bool VolumeImage::DetectProjection(VolumeProjection& projection, - bool& reverse, - const SliceGeometry& viewportSlice) - { - if (GeometryToolbox::IsParallelOrOpposite(reverse, viewportSlice.GetNormal(), axialGeometry_->GetNormal())) - { - projection = VolumeProjection_Axial; - return true; - } - else if (GeometryToolbox::IsParallelOrOpposite(reverse, viewportSlice.GetNormal(), sagittalGeometry_->GetNormal())) - { - projection = VolumeProjection_Sagittal; - return true; - } - else if (GeometryToolbox::IsParallelOrOpposite(reverse, viewportSlice.GetNormal(), coronalGeometry_->GetNormal())) - { - projection = VolumeProjection_Coronal; - return true; - } - else - { - return false; - } - } - - - const ParallelSlices& VolumeImage::GetGeometryInternal(VolumeProjection projection) - { - switch (projection) - { - case VolumeProjection_Axial: - return *axialGeometry_; - - case VolumeProjection_Sagittal: - return *sagittalGeometry_; - - case VolumeProjection_Coronal: - return *coronalGeometry_; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - } - - - bool VolumeImage::LayerFactory::GetExtent(double& x1, - double& y1, - double& x2, - double& y2, - const SliceGeometry& viewportSlice) - { - VolumeProjection projection; - bool reverse; - - if (that_.buffer_->GetWidth() == 0 || - that_.buffer_->GetHeight() == 0 || - that_.buffer_->GetDepth() == 0 || - !that_.DetectProjection(projection, reverse, viewportSlice)) - { - return false; - } - else - { - Vector spacing = that_.GetVoxelDimensions(projection); - - unsigned int width, height; - that_.buffer_->GetSliceSize(width, height, projection); - - // As the slices of the volumic image are arranged in a box, - // we only consider one single reference slice (the one with index 0). - const SliceGeometry& volumeSlice = that_.GetGeometryInternal(projection).GetSlice(0); - - return FrameRenderer::ComputeFrameExtent(x1, y1, x2, y2, - viewportSlice, volumeSlice, - width, height, - spacing[0], spacing[1]); - } - } - - - ILayerRenderer* VolumeImage::LayerFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice) - { - VolumeProjection projection; - bool reverse; - - if (that_.buffer_->GetWidth() == 0 || - that_.buffer_->GetHeight() == 0 || - that_.buffer_->GetDepth() == 0 || - !that_.DetectProjection(projection, reverse, viewportSlice)) - { - return NULL; - } - - const ParallelSlices& geometry = that_.GetGeometryInternal(projection); - - size_t closest; - double distance; - - const Vector spacing = that_.GetVoxelDimensions(projection); - const double sliceThickness = spacing[2]; - - if (geometry.ComputeClosestSlice(closest, distance, viewportSlice.GetOrigin()) && - distance <= sliceThickness / 2.0) - { - bool isFullQuality; - - if (projection == VolumeProjection_Axial && - that_.policy_.get() != NULL) - { - isFullQuality = that_.policy_->IsFullQualityAxial(closest); - } - else - { - isFullQuality = that_.IsLoadingComplete(); - } - - std::auto_ptr frame; - SliceGeometry frameSlice = geometry.GetSlice(closest); - - { - ImageBuffer3D::SliceReader reader(*that_.buffer_, projection, closest); - frame.reset(Orthanc::Image::Clone(reader.GetAccessor())); - } - - return FrameRenderer::CreateRenderer(frame.release(), - frameSlice, - *that_.referenceDataset_, - spacing[0], spacing[1], - isFullQuality); - } - else - { - return NULL; - } - } -} diff -r 6a7c702a7531 -r 71d574a3607f Framework/Volumes/VolumeImage.h --- a/Framework/Volumes/VolumeImage.h Wed Jun 14 14:21:24 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * 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 . - **/ - - -#pragma once - -#include "ISliceableVolume.h" -#include "ImageBuffer3D.h" -#include "../Toolbox/ISeriesLoader.h" -#include "../Toolbox/MessagingToolbox.h" -#include "../Toolbox/ObserversRegistry.h" -#include "../Layers/ILayerRendererFactory.h" - -#include - -namespace OrthancStone -{ - class VolumeImage : public ISliceableVolume - { - public: - class IDownloadPolicy : public boost::noncopyable - { - public: - virtual ~IDownloadPolicy() - { - } - - virtual void Initialize(ImageBuffer3D& buffer, - ISeriesLoader& loader) = 0; - - virtual void Finalize() = 0; - - // Must return "true" if the thread has completed its task. Pay - // attention that this method can be invoked concurrently by - // several download threads. - virtual bool DownloadStep(bool& complete) = 0; - - virtual bool IsFullQualityAxial(size_t slice) = 0; - }; - - - private: - std::auto_ptr loader_; - std::auto_ptr buffer_; - std::vector threads_; - bool started_; - bool continue_; - ObserversRegistry observers_; - bool loadingComplete_; - MessagingToolbox::Timestamp lastUpdate_; - std::auto_ptr referenceDataset_; - std::auto_ptr policy_; - - std::auto_ptr axialGeometry_; - std::auto_ptr coronalGeometry_; - std::auto_ptr sagittalGeometry_; - - void StoreUpdateTime(); - - void NotifyChange(bool force); - - static void LoadThread(VolumeImage* that); - - bool DetectProjection(VolumeProjection& projection, - bool& reverse, - const SliceGeometry& viewportSlice); - - const ParallelSlices& GetGeometryInternal(VolumeProjection projection); - - public: - VolumeImage(ISeriesLoader* loader); // Takes ownership - - virtual ~VolumeImage(); - - void SetDownloadPolicy(IDownloadPolicy* policy); // Takes ownership - - void SetThreadCount(size_t count); - - size_t GetThreadCount() const - { - return threads_.size(); - } - - virtual void Register(IObserver& observer); - - virtual void Unregister(IObserver& observer); - - virtual void Start(); - - virtual void Stop(); - - ParallelSlices* GetGeometry(VolumeProjection projection, - bool reverse); - - Vector GetVoxelDimensions(VolumeProjection projection) - { - return buffer_->GetVoxelDimensions(projection); - } - - bool IsLoadingComplete() const - { - return loadingComplete_; - } - - class LayerFactory : public ILayerRendererFactory - { - private: - VolumeImage& that_; - - public: - LayerFactory(VolumeImage& that) : - that_(that) - { - } - - virtual bool HasSourceVolume() const - { - return true; - } - - virtual ISliceableVolume& GetSourceVolume() const - { - return that_; - } - - virtual bool GetExtent(double& x1, - double& y1, - double& x2, - double& y2, - const SliceGeometry& viewportSlice); - - virtual ILayerRenderer* CreateLayerRenderer(const SliceGeometry& viewportSlice); - }; - }; -} diff -r 6a7c702a7531 -r 71d574a3607f Framework/Volumes/VolumeImagePolicyBase.cpp --- a/Framework/Volumes/VolumeImagePolicyBase.cpp Wed Jun 14 14:21:24 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * 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 . - **/ - - -#include "VolumeImagePolicyBase.h" - -namespace OrthancStone -{ - VolumeImagePolicyBase::VolumeImagePolicyBase() : - buffer_(NULL), - loader_(NULL) - { - } - - - void VolumeImagePolicyBase::Initialize(ImageBuffer3D& buffer, - ISeriesLoader& loader) - { - if (buffer_ != NULL || - loader_ != NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - buffer_ = &buffer; - loader_ = &loader; - - InitializeInternal(buffer, loader); - } - - - bool VolumeImagePolicyBase::DownloadStep(bool& complete) - { - if (buffer_ == NULL || - loader_ == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else - { - return DownloadStepInternal(complete, *buffer_, *loader_); - } - } -} diff -r 6a7c702a7531 -r 71d574a3607f Framework/Volumes/VolumeImagePolicyBase.h --- a/Framework/Volumes/VolumeImagePolicyBase.h Wed Jun 14 14:21:24 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * 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 . - **/ - - -#pragma once - -#include "VolumeImage.h" - -namespace OrthancStone -{ - class VolumeImagePolicyBase : public VolumeImage::IDownloadPolicy - { - private: - ImageBuffer3D* buffer_; - ISeriesLoader* loader_; - - protected: - virtual void InitializeInternal(ImageBuffer3D& buffer, - ISeriesLoader& loader) = 0; - - virtual bool DownloadStepInternal(bool& complete, - ImageBuffer3D& buffer, - ISeriesLoader& loader) = 0; - - public: - VolumeImagePolicyBase(); - - virtual void Initialize(ImageBuffer3D& buffer, - ISeriesLoader& loader); - - virtual void Finalize() - { - } - - virtual bool DownloadStep(bool& complete); - }; -} diff -r 6a7c702a7531 -r 71d574a3607f Framework/Volumes/VolumeImageProgressivePolicy.cpp --- a/Framework/Volumes/VolumeImageProgressivePolicy.cpp Wed Jun 14 14:21:24 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,202 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * 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 . - **/ - - -#include "VolumeImageProgressivePolicy.h" - -#include "../Toolbox/DownloadStack.h" -#include "../../Resources/Orthanc/Core/Images/ImageProcessing.h" - -namespace OrthancStone -{ - class VolumeImageProgressivePolicy::AxialSlicesScheduler - { - private: - size_t depth_; - DownloadStack stack_; - - public: - AxialSlicesScheduler(size_t depth) : - depth_(depth), - stack_(3 * depth) // "3" stands for the number of quality levels - { - assert(depth > 0); - } - - void TagFullPriority(int z, - int neighborhood) - { - DownloadStack::Writer writer(stack_); - - // Also schedule the neighboring slices for download in medium quality - for (int offset = neighborhood; offset >= 1; offset--) - { - writer.SetTopNodePermissive((z + offset) + depth_ * Quality_Medium); - writer.SetTopNodePermissive((z - offset) + depth_ * Quality_Medium); - } - - writer.SetTopNodePermissive(z + depth_ * Quality_Full); - } - - bool LookupSlice(unsigned int& z, - Quality& quality) - { - unsigned int value; - if (stack_.Pop(value)) - { - z = value % depth_; - - switch (value / depth_) - { - case 0: - quality = Quality_Low; - break; - - case 1: - quality = Quality_Medium; - break; - - case 2: - quality = Quality_Full; - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - return true; - } - else - { - return false; - } - } - }; - - - bool VolumeImageProgressivePolicy::IsComplete() - { - boost::mutex::scoped_lock lock(qualityMutex_); - - for (size_t i = 0; i < axialSlicesQuality_.size(); i++) - { - if (axialSlicesQuality_[i] != Quality_Full) - { - return false; - } - } - - return true; - } - - - void VolumeImageProgressivePolicy::InitializeInternal(ImageBuffer3D& buffer, - ISeriesLoader& loader) - { - const size_t depth = loader.GetGeometry().GetSliceCount(); - - isJpegAvailable_ = loader.IsJpegAvailable(); - - axialSlicesQuality_.clear(); - axialSlicesQuality_.resize(depth, Quality_None); - scheduler_.reset(new AxialSlicesScheduler(depth)); - } - - - bool VolumeImageProgressivePolicy::DownloadStepInternal(bool& complete, - ImageBuffer3D& buffer, - ISeriesLoader& loader) - { - unsigned int z; - Quality quality; - - if (!scheduler_->LookupSlice(z, quality)) - { - // There is no more frame to be downloaded. Before stopping, - // each loader thread checks whether all the frames have been - // downloaded at maximum quality. - complete = IsComplete(); - return true; - } - - if (quality != Quality_Full && - !isJpegAvailable_) - { - // Cannot fulfill this command, as progressive JPEG download - // is unavailable (i.e. the Web viewer plugin is unavailable) - return false; - } - - std::auto_ptr frame; - - try - { - switch (quality) - { - case Quality_Low: - frame.reset(loader.DownloadJpegFrame(z, 10)); - break; - - case Quality_Medium: - frame.reset(loader.DownloadJpegFrame(z, 90)); - break; - - case Quality_Full: - frame.reset(loader.DownloadFrame(z)); - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - catch (Orthanc::OrthancException&) - { - // The Orthanc server cannot decode this instance - return false; - } - - if (frame.get() != NULL) - { - boost::mutex::scoped_lock lock(qualityMutex_); - - if (axialSlicesQuality_[z] == Quality_None || - axialSlicesQuality_[z] < quality) - { - axialSlicesQuality_[z] = quality; - - ImageBuffer3D::SliceWriter writer(buffer, VolumeProjection_Axial, z); - Orthanc::ImageProcessing::Convert(writer.GetAccessor(), *frame); - } - } - - return false; - } - - - bool VolumeImageProgressivePolicy::IsFullQualityAxial(size_t slice) - { - scheduler_->TagFullPriority(slice, 3); - - { - boost::mutex::scoped_lock lock(qualityMutex_); - return (axialSlicesQuality_[slice] == Quality_Full); - } - } -} diff -r 6a7c702a7531 -r 71d574a3607f Framework/Volumes/VolumeImageProgressivePolicy.h --- a/Framework/Volumes/VolumeImageProgressivePolicy.h Wed Jun 14 14:21:24 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * 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 . - **/ - - -#pragma once - -#include "VolumeImagePolicyBase.h" - -namespace OrthancStone -{ - class VolumeImageProgressivePolicy : public VolumeImagePolicyBase - { - private: - enum Quality - { - Quality_Low = 0, - Quality_Medium = 1, - Quality_Full = 2, - Quality_None = 3 - }; - - class AxialSlicesScheduler; - - std::auto_ptr scheduler_; - boost::mutex qualityMutex_; - std::vector axialSlicesQuality_; - bool isJpegAvailable_; - - bool IsComplete(); - - protected: - virtual void InitializeInternal(ImageBuffer3D& buffer, - ISeriesLoader& loader); - - virtual bool DownloadStepInternal(bool& complete, - ImageBuffer3D& buffer, - ISeriesLoader& loader); - - public: - virtual bool IsFullQualityAxial(size_t slice); - }; -} diff -r 6a7c702a7531 -r 71d574a3607f Framework/Volumes/VolumeImageSimplePolicy.cpp --- a/Framework/Volumes/VolumeImageSimplePolicy.cpp Wed Jun 14 14:21:24 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * 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 . - **/ - - -#include "VolumeImageSimplePolicy.h" - -#include "../../Resources/Orthanc/Core/Images/ImageProcessing.h" - -namespace OrthancStone -{ - void VolumeImageSimplePolicy::InitializeInternal(ImageBuffer3D& buffer, - ISeriesLoader& loader) - { - boost::mutex::scoped_lock lock(mutex_); - - const size_t depth = loader.GetGeometry().GetSliceCount(); - pendingSlices_.clear(); - - for (size_t i = 0; i < depth; i++) - { - pendingSlices_.insert(i); - } - - doneSlices_.clear(); - doneSlices_.resize(depth, false); - } - - - bool VolumeImageSimplePolicy::DownloadStepInternal(bool& complete, - ImageBuffer3D& buffer, - ISeriesLoader& loader) - { - size_t slice; - - { - boost::mutex::scoped_lock lock(mutex_); - - if (pendingSlices_.empty()) - { - return true; - } - else - { - slice = *pendingSlices_.begin(); - pendingSlices_.erase(slice); - } - } - - std::auto_ptr frame; - - try - { - frame.reset(loader.DownloadFrame(slice)); - } - catch (Orthanc::OrthancException&) - { - // The Orthanc server cannot decode this instance - return false; - } - - if (frame.get() != NULL) - { - { - ImageBuffer3D::SliceWriter writer(buffer, VolumeProjection_Axial, slice); - Orthanc::ImageProcessing::Convert(writer.GetAccessor(), *frame); - } - - { - boost::mutex::scoped_lock lock(mutex_); - - doneSlices_[slice] = true; - - if (pendingSlices_.empty()) - { - complete = true; - return true; - } - } - } - - return false; - } - - - bool VolumeImageSimplePolicy::IsFullQualityAxial(size_t slice) - { - boost::mutex::scoped_lock lock(mutex_); - return doneSlices_[slice]; - } -} diff -r 6a7c702a7531 -r 71d574a3607f Framework/Volumes/VolumeImageSimplePolicy.h --- a/Framework/Volumes/VolumeImageSimplePolicy.h Wed Jun 14 14:21:24 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * 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 . - **/ - - -#pragma once - -#include "VolumeImagePolicyBase.h" - -namespace OrthancStone -{ - class VolumeImageSimplePolicy : public VolumeImagePolicyBase - { - private: - boost::mutex mutex_; - std::set pendingSlices_; - std::vector doneSlices_; - - protected: - virtual void InitializeInternal(ImageBuffer3D& buffer, - ISeriesLoader& loader); - - virtual bool DownloadStepInternal(bool& complete, - ImageBuffer3D& buffer, - ISeriesLoader& loader); - - public: - virtual bool IsFullQualityAxial(size_t slice); - }; -} diff -r 6a7c702a7531 -r 71d574a3607f Framework/Widgets/LayeredSceneWidget.cpp --- a/Framework/Widgets/LayeredSceneWidget.cpp Wed Jun 14 14:21:24 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,595 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * 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 . - **/ - - -#define _USE_MATH_DEFINES // To access M_PI in Visual Studio -#include - -#include "LayeredSceneWidget.h" - -#include "../../Resources/Orthanc/Core/OrthancException.h" - -#include // TODO Remove - -namespace OrthancStone -{ - class LayeredSceneWidget::Renderers : public boost::noncopyable - { - private: - boost::mutex mutex_; - std::vector renderers_; - std::vector assigned_; - - void Assign(size_t index, - ILayerRenderer* renderer) - { - if (index >= renderers_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - if (renderers_[index] != NULL) - { - delete renderers_[index]; - } - - renderers_[index] = renderer; - assigned_[index] = true; - } - - public: - Renderers(size_t size) - { - renderers_.resize(size); - assigned_.resize(size, false); - } - - ~Renderers() - { - for (size_t i = 0; i < renderers_.size(); i++) - { - Assign(i, NULL); - } - } - - static void Merge(Renderers& target, - Renderers& source) - { - boost::mutex::scoped_lock lockSource(source.mutex_); - boost::mutex::scoped_lock lockTarget(target.mutex_); - - size_t count = target.renderers_.size(); - if (count != source.renderers_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - for (size_t i = 0; i < count; i++) - { - if (source.assigned_[i]) - { - target.Assign(i, source.renderers_[i]); // Transfers ownership - source.renderers_[i] = NULL; - source.assigned_[i] = false; - } - } - } - - void SetRenderer(size_t index, - ILayerRenderer* renderer) // Takes ownership - { - boost::mutex::scoped_lock lock(mutex_); - Assign(index, renderer); - } - - bool RenderScene(CairoContext& context, - const ViewportGeometry& view, - const SliceGeometry& slice) - { - boost::mutex::scoped_lock lock(mutex_); - - bool fullQuality = true; - - for (size_t i = 0; i < renderers_.size(); i++) - { - if (renderers_[i] != NULL && - !renderers_[i]->RenderLayer(context, view, slice)) - { - return false; - } - - if (renderers_[i] != NULL && - !renderers_[i]->IsFullQuality()) - { - fullQuality = false; - } - } - - if (!fullQuality) - { - double x, y; - view.MapDisplayToScene(x, y, static_cast(view.GetDisplayWidth()) / 2.0, 10); - - cairo_t *cr = context.GetObject(); - cairo_translate(cr, x, y); - cairo_arc(cr, 0, 0, 5.0 / view.GetZoom(), 0, 2 * M_PI); - cairo_set_line_width(cr, 2.0 / view.GetZoom()); - cairo_set_source_rgb(cr, 1, 1, 1); - cairo_stroke_preserve(cr); - cairo_set_source_rgb(cr, 1, 0, 0); - cairo_fill(cr); - } - - return true; - } - - void SetLayerStyle(size_t index, - const RenderStyle& style) - { - boost::mutex::scoped_lock lock(mutex_); - - if (renderers_[index] != NULL) - { - renderers_[index]->SetLayerStyle(style); - } - } - }; - - - - class LayeredSceneWidget::PendingLayers : public boost::noncopyable - { - private: - boost::mutex mutex_; - boost::condition_variable elementAvailable_; - size_t layerCount_; - std::list queue_; - std::vector layersToUpdate_; - bool continue_; - - void TagAllLayers() - { - queue_.clear(); - - for (unsigned int i = 0; i < layerCount_; i++) - { - queue_.push_back(i); - layersToUpdate_[i] = true; - } - - if (layerCount_ != 0) - { - elementAvailable_.notify_one(); - } - } - - public: - PendingLayers() : - layerCount_(0), - continue_(true) - { - } - - void Stop() - { - continue_ = false; - elementAvailable_.notify_one(); - } - - void SetLayerCount(size_t count) - { - boost::mutex::scoped_lock lock(mutex_); - - layerCount_ = count; - layersToUpdate_.resize(count); - - TagAllLayers(); - } - - void InvalidateAllLayers() - { - boost::mutex::scoped_lock lock(mutex_); - TagAllLayers(); - } - - void InvalidateLayer(size_t layer) - { - boost::mutex::scoped_lock lock(mutex_); - - if (layer < layerCount_) - { - if (layersToUpdate_[layer]) - { - // The layer is already scheduled for update, ignore this - // invalidation - } - else - { - queue_.push_back(layer); - layersToUpdate_[layer] = true; - elementAvailable_.notify_one(); - } - } - } - - bool Dequeue(size_t& layer, - bool& isLast) - { - boost::mutex::scoped_lock lock(mutex_); - - // WARNING: Do NOT use "timed_wait" on condition variables, as - // sleeping is not properly supported by Boost for Google NaCl - while (queue_.empty() && - continue_) - { - elementAvailable_.wait(lock); - } - - if (!continue_) - { - return false; - } - - layer = queue_.front(); - layersToUpdate_[layer] = false; - queue_.pop_front(); - - isLast = queue_.empty(); - - return true; - } - }; - - - class LayeredSceneWidget::Layer : public ISliceableVolume::IObserver - { - private: - boost::mutex mutex_; - std::auto_ptr factory_; - PendingLayers& layers_; - size_t index_; - std::auto_ptr style_; - - public: - Layer(ILayerRendererFactory* factory, - PendingLayers& layers, - size_t index) : - factory_(factory), - layers_(layers), - index_(index) - { - if (factory == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - } - - virtual void NotifyChange(const OrthancStone::ISliceableVolume&) - { - layers_.InvalidateLayer(index_); - } - - void Start() - { - if (factory_->HasSourceVolume()) - { - factory_->GetSourceVolume().Register(*this); - } - } - - void Stop() - { - if (factory_->HasSourceVolume()) - { - factory_->GetSourceVolume().Unregister(*this); - } - } - - bool GetExtent(double& x1, - double& y1, - double& x2, - double& y2, - const SliceGeometry& displaySlice) - { - boost::mutex::scoped_lock lock(mutex_); - assert(factory_.get() != NULL); - return factory_->GetExtent(x1, y1, x2, y2, displaySlice); - } - - RenderStyle GetStyle() - { - boost::mutex::scoped_lock lock(mutex_); - - if (style_.get() == NULL) - { - return RenderStyle(); - } - else - { - return *style_; - } - } - - void SetStyle(const RenderStyle& style) - { - boost::mutex::scoped_lock lock(mutex_); - style_.reset(new RenderStyle(style)); - } - - - ILayerRenderer* CreateRenderer(const SliceGeometry& displaySlice) - { - boost::mutex::scoped_lock lock(mutex_); - assert(factory_.get() != NULL); - - std::auto_ptr renderer(factory_->CreateLayerRenderer(displaySlice)); - - if (renderer.get() != NULL && - style_.get() != NULL) - { - renderer->SetLayerStyle(*style_); - } - - return renderer.release(); - } - }; - - - - SliceGeometry LayeredSceneWidget::GetSlice() - { - boost::mutex::scoped_lock lock(sliceMutex_); - return slice_; - } - - - void LayeredSceneWidget::UpdateContent() - { - size_t layer = 0; - bool isLast = true; - if (!pendingLayers_->Dequeue(layer, isLast)) - { - return; - } - - SliceGeometry slice = GetSlice(); - - std::auto_ptr renderer; - renderer.reset(layers_[layer]->CreateRenderer(slice)); - - if (renderer.get() != NULL) - { - pendingRenderers_->SetRenderer(layer, renderer.release()); - } - else - { - pendingRenderers_->SetRenderer(layer, NULL); - } - - if (isLast) - { - Renderers::Merge(*renderers_, *pendingRenderers_); - NotifyChange(); - } - - // TODO Add sleep at this point - } - - - bool LayeredSceneWidget::RenderScene(CairoContext& context, - const ViewportGeometry& view) - { - return renderers_->RenderScene(context, view, slice_); - } - - - LayeredSceneWidget::LayeredSceneWidget() - { - pendingLayers_.reset(new PendingLayers); - SetBackgroundCleared(true); - } - - - LayeredSceneWidget::~LayeredSceneWidget() - { - for (size_t i = 0; i < layers_.size(); i++) - { - assert(layers_[i] != NULL); - delete layers_[i]; - } - } - - - void LayeredSceneWidget::GetSceneExtent(double& x1, - double& y1, - double& x2, - double& y2) - { - boost::mutex::scoped_lock lock(sliceMutex_); - - bool first = true; - - for (size_t i = 0; i < layers_.size(); i++) - { - double ax, ay, bx, by; - - assert(layers_[i] != NULL); - if (layers_[i]->GetExtent(ax, ay, bx, by, slice_)) - { - if (ax > bx) - { - std::swap(ax, bx); - } - - if (ay > by) - { - std::swap(ay, by); - } - - if (first) - { - x1 = ax; - y1 = ay; - x2 = bx; - y2 = by; - first = false; - } - else - { - x1 = std::min(x1, ax); - y1 = std::min(y1, ay); - x2 = std::max(x2, bx); - y2 = std::max(y2, by); - } - } - } - - if (first) - { - x1 = -1; - y1 = -1; - x2 = 1; - y2 = 1; - } - - // Ensure the extent is non-empty - if (x1 >= x2) - { - double tmp = x1; - x1 = tmp - 0.5; - x2 = tmp + 0.5; - } - - if (y1 >= y2) - { - double tmp = y1; - y1 = tmp - 0.5; - y2 = tmp + 0.5; - } - } - - - - ILayerRendererFactory& LayeredSceneWidget::AddLayer(size_t& layerIndex, - ILayerRendererFactory* factory) - { - layerIndex = layers_.size(); - layers_.push_back(new Layer(factory, *pendingLayers_, layers_.size())); - - return *factory; - } - - - void LayeredSceneWidget::AddLayer(ILayerRendererFactory* factory) - { - size_t layerIndex; // Ignored - AddLayer(layerIndex, factory); - } - - - RenderStyle LayeredSceneWidget::GetLayerStyle(size_t layer) - { - if (layer >= layers_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - return layers_[layer]->GetStyle(); - } - - - void LayeredSceneWidget::SetLayerStyle(size_t layer, - const RenderStyle& style) - { - if (layer >= layers_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - layers_[layer]->SetStyle(style); - - if (renderers_.get() != NULL) - { - renderers_->SetLayerStyle(layer, style); - } - - InvalidateLayer(layer); - } - - - - void LayeredSceneWidget::SetSlice(const SliceGeometry& slice) - { - { - boost::mutex::scoped_lock lock(sliceMutex_); - slice_ = slice; - } - - InvalidateAllLayers(); - - observers_.Apply(*this, &ISliceObserver::NotifySliceChange, slice); - } - - - void LayeredSceneWidget::InvalidateLayer(unsigned int layer) - { - pendingLayers_->InvalidateLayer(layer); - //NotifyChange(); // TODO Understand why this makes the SDL engine not update the display subsequently - } - - - void LayeredSceneWidget::InvalidateAllLayers() - { - pendingLayers_->InvalidateAllLayers(); - //NotifyChange(); // TODO Understand why this makes the SDL engine not update the display subsequently - } - - -#if 0 - void LayeredSceneWidget::Start() - { - for (size_t i = 0; i < layers_.size(); i++) - { - layers_[i]->Start(); - } - - renderers_.reset(new Renderers(layers_.size())); - pendingRenderers_.reset(new Renderers(layers_.size())); - - pendingLayers_->SetLayerCount(layers_.size()); - - WorldSceneWidget::Start(); - } - - - void LayeredSceneWidget::Stop() - { - pendingLayers_->Stop(); - - renderers_.reset(NULL); - pendingRenderers_.reset(NULL); - - for (size_t i = 0; i < layers_.size(); i++) - { - layers_[i]->Stop(); - } - } -#endif -} diff -r 6a7c702a7531 -r 71d574a3607f Framework/Widgets/LayeredSceneWidget.h --- a/Framework/Widgets/LayeredSceneWidget.h Wed Jun 14 14:21:24 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * 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 . - **/ - - -#pragma once - -#include "WorldSceneWidget.h" - -#include "../Layers/ILayerRendererFactory.h" -#include "../Toolbox/ObserversRegistry.h" - -#include // TODO remove - -namespace OrthancStone -{ - class LayeredSceneWidget : public WorldSceneWidget - { - public: - class ISliceObserver : public boost::noncopyable - { - public: - virtual ~ISliceObserver() - { - } - - virtual void NotifySliceChange(const LayeredSceneWidget& source, - const SliceGeometry& slice) = 0; - }; - - private: - class Renderers; - class PendingLayers; - class Layer; - - typedef ObserversRegistry Observers; - - std::vector layers_; - std::auto_ptr renderers_; - std::auto_ptr pendingLayers_; - std::auto_ptr pendingRenderers_; - boost::mutex sliceMutex_; - SliceGeometry slice_; - Observers observers_; - - protected: - virtual void GetSceneExtent(double& x1, - double& y1, - double& x2, - double& y2); - - virtual bool RenderScene(CairoContext& context, - const ViewportGeometry& view); - - public: - LayeredSceneWidget(); - - virtual ~LayeredSceneWidget(); - - SliceGeometry GetSlice(); - - ILayerRendererFactory& AddLayer(size_t& layerIndex, - ILayerRendererFactory* factory); // Takes ownership - - // Simpler version for basic use cases - void AddLayer(ILayerRendererFactory* factory); // Takes ownership - - size_t GetLayerCount() const - { - return layers_.size(); - } - - RenderStyle GetLayerStyle(size_t layer); - - void SetLayerStyle(size_t layer, - const RenderStyle& style); - - void SetSlice(const SliceGeometry& slice); - - void InvalidateLayer(unsigned int layer); - - void InvalidateAllLayers(); - - using WorldSceneWidget::Register; - using WorldSceneWidget::Unregister; - - void Register(ISliceObserver& observer) - { - observers_.Register(observer); - } - - void Unregister(ISliceObserver& observer) - { - observers_.Unregister(observer); - } - - virtual bool HasUpdateContent() const - { - return true; - } - - virtual void UpdateContent(); - }; -} diff -r 6a7c702a7531 -r 71d574a3607f Resources/CMake/OrthancStone.cmake --- a/Resources/CMake/OrthancStone.cmake Wed Jun 14 14:21:24 2017 +0200 +++ b/Resources/CMake/OrthancStone.cmake Wed Jun 14 15:07:07 2017 +0200 @@ -193,11 +193,6 @@ #${ORTHANC_STONE_DIR}/Framework/Layers/SeriesFrameRendererFactory.cpp #${ORTHANC_STONE_DIR}/Framework/Layers/SiblingSliceLocationFactory.cpp #${ORTHANC_STONE_DIR}/Framework/Layers/SingleFrameRendererFactory.cpp - #${ORTHANC_STONE_DIR}/Framework/Volumes/VolumeImage.cpp - #${ORTHANC_STONE_DIR}/Framework/Volumes/VolumeImagePolicyBase.cpp - #${ORTHANC_STONE_DIR}/Framework/Volumes/VolumeImageProgressivePolicy.cpp - #${ORTHANC_STONE_DIR}/Framework/Volumes/VolumeImageSimplePolicy.cpp - #${ORTHANC_STONE_DIR}/Framework/Widgets/LayeredSceneWidget.cpp ${ORTHANC_STONE_DIR}/Framework/Layers/CircleMeasureTracker.cpp ${ORTHANC_STONE_DIR}/Framework/Layers/ColorFrameRenderer.cpp ${ORTHANC_STONE_DIR}/Framework/Layers/FrameRenderer.cpp