changeset 811:ffec76a5f7eb

deprecating ParallelSlices
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 28 May 2019 18:21:00 +0200
parents 7608e8107aa1
children bc7ee59420a1
files Framework/Deprecated/Toolbox/ParallelSlices.cpp Framework/Deprecated/Toolbox/ParallelSlices.h Framework/Deprecated/Toolbox/ParallelSlicesCursor.cpp Framework/Deprecated/Toolbox/ParallelSlicesCursor.h Framework/Toolbox/FiniteProjectiveCamera.cpp Framework/Toolbox/ParallelSlices.cpp Framework/Toolbox/ParallelSlices.h Framework/Toolbox/ParallelSlicesCursor.cpp Framework/Toolbox/ParallelSlicesCursor.h Framework/Volumes/VolumeImageGeometry.cpp Framework/Volumes/VolumeImageGeometry.h Resources/CMake/OrthancStoneConfiguration.cmake
diffstat 12 files changed, 585 insertions(+), 586 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/ParallelSlices.cpp	Tue May 28 18:21:00 2019 +0200
@@ -0,0 +1,215 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 Osimis S.A., 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 <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "ParallelSlices.h"
+
+#include "../../Toolbox/GeometryToolbox.h"
+#include "../../Volumes/ImageBuffer3D.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+namespace Deprecated
+{
+  ParallelSlices::ParallelSlices()
+  {
+    Clear();
+  }
+
+
+  ParallelSlices::ParallelSlices(const ParallelSlices& other)
+  {
+    normal_ = other.normal_;
+
+    slices_.resize(other.slices_.size());
+
+    for (size_t i = 0; i < slices_.size(); i++)
+    {
+      assert(other.slices_[i] != NULL);
+      slices_[i] = new OrthancStone::CoordinateSystem3D(*other.slices_[i]);
+    }
+  }
+
+
+  void ParallelSlices::Clear()
+  {
+    for (size_t i = 0; i < slices_.size(); i++)
+    {
+      if (slices_[i] != NULL)
+      {
+        delete slices_[i];
+        slices_[i] = NULL;
+      }
+    }
+
+    slices_.clear();
+    OrthancStone::LinearAlgebra::AssignVector(normal_, 0, 0, 1);
+  }
+  
+
+  ParallelSlices::~ParallelSlices()
+  {
+    Clear();
+  }
+
+
+  void ParallelSlices::AddSlice(const OrthancStone::CoordinateSystem3D& slice)
+  {
+    if (slices_.empty())
+    {
+      normal_ = slice.GetNormal();
+      slices_.push_back(new OrthancStone::CoordinateSystem3D(slice));
+    }
+    else if (OrthancStone::GeometryToolbox::IsParallel(slice.GetNormal(), normal_))
+    {
+      slices_.push_back(new OrthancStone::CoordinateSystem3D(slice));
+    }
+    else
+    {
+      LOG(ERROR) << "Trying to add a slice that is not parallel to the previous ones";
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+
+
+  void ParallelSlices::AddSlice(const OrthancStone::Vector& origin,
+                                const OrthancStone::Vector& axisX,
+                                const OrthancStone::Vector& axisY)
+  {
+    OrthancStone::CoordinateSystem3D slice(origin, axisX, axisY);
+    AddSlice(slice);
+  }
+
+
+  const OrthancStone::CoordinateSystem3D& ParallelSlices::GetSlice(size_t index) const
+  {
+    if (index >= slices_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      return *slices_[index];
+    }
+  }
+
+
+  bool ParallelSlices::ComputeClosestSlice(size_t& closestSlice,
+                                           double& closestDistance,
+                                           const OrthancStone::Vector& origin) const
+  {
+    if (slices_.empty())
+    {
+      return false;
+    }
+
+    double reference = boost::numeric::ublas::inner_prod(origin, normal_);
+
+    closestSlice = 0;
+    closestDistance = std::numeric_limits<double>::infinity();
+
+    for (size_t i = 0; i < slices_.size(); i++)
+    {
+      double distance = fabs(boost::numeric::ublas::inner_prod(slices_[i]->GetOrigin(), normal_) - reference);
+
+      if (distance < closestDistance)
+      {
+        closestSlice = i;
+        closestDistance = distance;
+      }
+    }
+
+    return true;
+  }
+
+
+  ParallelSlices* ParallelSlices::Reverse() const
+  {
+    std::auto_ptr<ParallelSlices> reversed(new ParallelSlices);
+
+    for (size_t i = slices_.size(); i > 0; i--)
+    {
+      const OrthancStone::CoordinateSystem3D& slice = *slices_[i - 1];
+
+      reversed->AddSlice(slice.GetOrigin(),
+                         -slice.GetAxisX(),
+                         slice.GetAxisY());
+    }
+
+    return reversed.release();
+  }
+
+
+  ParallelSlices* ParallelSlices::FromVolumeImage(const OrthancStone::VolumeImageGeometry& geometry,
+                                                  OrthancStone::VolumeProjection projection)
+  {
+    const OrthancStone::Vector dimensions = geometry.GetVoxelDimensions(OrthancStone::VolumeProjection_Axial);
+    const OrthancStone::CoordinateSystem3D& axial = geometry.GetAxialGeometry();
+    
+    std::auto_ptr<ParallelSlices> result(new ParallelSlices);
+
+    switch (projection)
+    {
+      case OrthancStone::VolumeProjection_Axial:
+        for (unsigned int z = 0; z < geometry.GetDepth(); z++)
+        {
+          OrthancStone::Vector origin = axial.GetOrigin();
+          origin += static_cast<double>(z) * dimensions[2] * axial.GetNormal();
+
+          result->AddSlice(origin,
+                           axial.GetAxisX(),
+                           axial.GetAxisY());
+        }
+        break;
+
+      case OrthancStone::VolumeProjection_Coronal:
+        for (unsigned int y = 0; y < geometry.GetHeight(); y++)
+        {
+          OrthancStone::Vector origin = axial.GetOrigin();
+          origin += static_cast<double>(y) * dimensions[1] * axial.GetAxisY();
+          origin += static_cast<double>(geometry.GetDepth() - 1) * dimensions[2] * axial.GetNormal();
+
+          result->AddSlice(origin,
+                           axial.GetAxisX(),
+                           -axial.GetNormal());
+        }
+        break;
+
+      case OrthancStone::VolumeProjection_Sagittal:
+        for (unsigned int x = 0; x < geometry.GetWidth(); x++)
+        {
+          OrthancStone::Vector origin = axial.GetOrigin();
+          origin += static_cast<double>(x) * dimensions[0] * axial.GetAxisX();
+          origin += static_cast<double>(geometry.GetDepth() - 1) * dimensions[2] * axial.GetNormal();
+
+          result->AddSlice(origin,
+                           axial.GetAxisY(),
+                           -axial.GetNormal());
+        }
+        break;
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    return result.release();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/ParallelSlices.h	Tue May 28 18:21:00 2019 +0200
@@ -0,0 +1,73 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 Osimis S.A., 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 <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "../../Toolbox/CoordinateSystem3D.h"
+#include "../../Volumes/VolumeImageGeometry.h"
+
+namespace Deprecated
+{
+  class ParallelSlices : public boost::noncopyable
+  {
+  private:
+    OrthancStone::Vector  normal_;
+    std::vector<OrthancStone::CoordinateSystem3D*>  slices_;
+    
+    ParallelSlices& operator= (const ParallelSlices& other);  // Forbidden
+
+    void Clear();
+
+  public:
+    ParallelSlices();
+
+    ParallelSlices(const ParallelSlices& other);
+
+    ~ParallelSlices();
+
+    const OrthancStone::Vector& GetNormal() const
+    {
+      return normal_;
+    }
+
+    void AddSlice(const OrthancStone::CoordinateSystem3D& slice);
+
+    void AddSlice(const OrthancStone::Vector& origin,
+                  const OrthancStone::Vector& axisX,
+                  const OrthancStone::Vector& axisY);
+
+    size_t GetSliceCount() const
+    {
+      return slices_.size();
+    }
+
+    const OrthancStone::CoordinateSystem3D& GetSlice(size_t index) const;
+
+    bool ComputeClosestSlice(size_t& closestSlice,
+                             double& closestDistance,
+                             const OrthancStone::Vector& origin) const;
+
+    ParallelSlices* Reverse() const;
+
+    static ParallelSlices* FromVolumeImage(const OrthancStone::VolumeImageGeometry& geometry,
+                                           OrthancStone::VolumeProjection projection);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/ParallelSlicesCursor.cpp	Tue May 28 18:21:00 2019 +0200
@@ -0,0 +1,221 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 Osimis S.A., 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 <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "ParallelSlicesCursor.h"
+
+#include <Core/OrthancException.h>
+
+namespace Deprecated
+{
+  size_t ParallelSlicesCursor::GetDefaultSlice()
+  {
+    if (slices_.get() == NULL)
+    {
+      return 0;
+    }
+    else
+    {
+      return slices_->GetSliceCount() / 2;
+    }
+  }
+
+
+  size_t ParallelSlicesCursor::GetSliceCount()
+  {
+    if (slices_.get() == NULL)
+    {
+      return 0;
+    }
+    else
+    {
+      return slices_->GetSliceCount();
+    }
+  }
+
+
+  OrthancStone::CoordinateSystem3D ParallelSlicesCursor::GetSlice(size_t slice)
+  {
+    if (slices_.get() == NULL)
+    {
+      return OrthancStone::CoordinateSystem3D();
+    }
+    else
+    {
+      return slices_->GetSlice(slice);
+    }
+  }
+
+
+  void ParallelSlicesCursor::SetGeometry(const ParallelSlices& slices)
+  {
+    slices_.reset(new ParallelSlices(slices));
+
+    currentSlice_ = GetDefaultSlice();
+  }
+
+
+  OrthancStone::CoordinateSystem3D ParallelSlicesCursor::GetCurrentSlice()
+  {
+    if (slices_.get() != NULL &&
+        currentSlice_ < slices_->GetSliceCount())
+    {
+      return slices_->GetSlice(currentSlice_);
+    }
+    else
+    {
+      return OrthancStone::CoordinateSystem3D();  // No slice is available, return the canonical geometry
+    }
+  }
+
+
+  bool ParallelSlicesCursor::SetDefaultSlice()
+  {
+    size_t slice = GetDefaultSlice();
+
+    if (currentSlice_ != slice)
+    {
+      currentSlice_ = slice;
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+  bool ParallelSlicesCursor::ApplyOffset(OrthancStone::SliceOffsetMode mode,
+                                         int offset)
+  {
+    if (slices_.get() == NULL)
+    {
+      return false;
+    }
+
+    int count = static_cast<int>(slices_->GetSliceCount());
+    if (count == 0)
+    {
+      return false;
+    }
+
+    int slice;
+    if (static_cast<int>(currentSlice_) >= count)
+    {
+      slice = count - 1;
+    }
+    else
+    {
+      slice = static_cast<int>(currentSlice_);
+    }
+
+    switch (mode)
+    {
+      case OrthancStone::SliceOffsetMode_Absolute:
+      {
+        slice = offset;
+        break;
+      }
+
+      case OrthancStone::SliceOffsetMode_Relative:
+      {
+        slice += offset;
+        break;
+      }
+
+      case OrthancStone::SliceOffsetMode_Loop:
+      {
+        slice += offset;
+        while (slice < 0)
+        {
+          slice += count;
+        }
+
+        while (slice >= count)
+        {
+          slice -= count;
+        }
+
+        break;
+      }
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    if (slice < 0)
+    {
+      slice = 0;
+    }
+
+    if (slice >= count)
+    {
+      slice = count - 1;
+    }
+
+    if (slice != static_cast<int>(currentSlice_))
+    {
+      currentSlice_ = static_cast<int>(slice);
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+  bool ParallelSlicesCursor::ApplyWheelEvent(OrthancStone::MouseWheelDirection direction,
+                                             OrthancStone::KeyboardModifiers modifiers)
+  {
+    int offset = (modifiers & OrthancStone::KeyboardModifiers_Control ? 10 : 1);
+
+    switch (direction)
+    {
+      case OrthancStone::MouseWheelDirection_Down:
+        return ApplyOffset(OrthancStone::SliceOffsetMode_Relative, -offset);
+
+      case OrthancStone::MouseWheelDirection_Up:
+        return ApplyOffset(OrthancStone::SliceOffsetMode_Relative, offset);
+
+      default:
+        return false;
+    }
+  }
+
+
+  bool ParallelSlicesCursor::LookupSliceContainingPoint(const OrthancStone::Vector& p)
+  {
+    size_t slice;
+    double distance;
+
+    if (slices_.get() != NULL &&
+        slices_->ComputeClosestSlice(slice, distance, p))
+    {
+      if (currentSlice_ != slice)
+      {
+        currentSlice_ = slice;
+        return true;
+      }
+    }
+
+    return false;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/ParallelSlicesCursor.h	Tue May 28 18:21:00 2019 +0200
@@ -0,0 +1,65 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 Osimis S.A., 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 <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "ParallelSlices.h"
+#include "../../StoneEnumerations.h"
+
+namespace Deprecated
+{
+  class ParallelSlicesCursor : public boost::noncopyable
+  {
+  private:
+    std::auto_ptr<ParallelSlices>  slices_;
+    size_t                         currentSlice_;
+
+    size_t GetDefaultSlice();
+
+  public:
+    ParallelSlicesCursor() :
+      currentSlice_(0)
+    {
+    }
+
+    void SetGeometry(const ParallelSlices& slices);
+
+    size_t GetSliceCount();
+
+    OrthancStone::CoordinateSystem3D GetSlice(size_t slice);
+
+    OrthancStone::CoordinateSystem3D GetCurrentSlice();
+
+    // Returns "true" iff. the slice has actually changed
+    bool SetDefaultSlice();
+
+    // Returns "true" iff. the slice has actually changed
+    bool ApplyOffset(OrthancStone::SliceOffsetMode mode,
+                     int offset);
+
+    // Returns "true" iff. the slice has actually changed
+    bool ApplyWheelEvent(OrthancStone::MouseWheelDirection direction,
+                         OrthancStone::KeyboardModifiers modifiers);
+
+    // Returns "true" iff. the slice has actually changed
+    bool LookupSliceContainingPoint(const OrthancStone::Vector& p);
+  };
+}
--- a/Framework/Toolbox/FiniteProjectiveCamera.cpp	Tue May 28 18:09:48 2019 +0200
+++ b/Framework/Toolbox/FiniteProjectiveCamera.cpp	Tue May 28 18:21:00 2019 +0200
@@ -23,7 +23,6 @@
 
 #include "GeometryToolbox.h"
 #include "SubpixelReader.h"
-#include "ParallelSlices.h"
 
 #include <Core/Logging.h>
 #include <Core/OrthancException.h>
@@ -317,7 +316,7 @@
     LOG(WARNING) << "Output image size: " << target.GetWidth() << "x" << target.GetHeight();
     LOG(WARNING) << "Output pixel format: " << Orthanc::EnumerationToString(target.GetFormat());
 
-    std::auto_ptr<OrthancStone::ParallelSlices> slices(OrthancStone::ParallelSlices::FromVolumeImage(geometry, projection));
+    const unsigned int slicesCount = geometry.GetProjectionDepth(projection);
     const OrthancStone::Vector pixelSpacing = geometry.GetVoxelDimensions(projection);
     const unsigned int targetWidth = target.GetWidth();
     const unsigned int targetHeight = target.GetHeight();
@@ -329,11 +328,11 @@
 
     typedef SubpixelReader<SourceFormat, ImageInterpolation_Nearest>  SourceReader;
     
-    for (size_t z = 0; z < slices->GetSliceCount(); z++)
+    for (unsigned int z = 0; z < slicesCount; z++)
     {
-      LOG(INFO) << "Applying raytracer on slice: " << z << "/" << slices->GetSliceCount();
-      
-      const OrthancStone::CoordinateSystem3D& slice = slices->GetSlice(z);
+      LOG(INFO) << "Applying raytracer on slice: " << z << "/" << slicesCount;
+
+      OrthancStone::CoordinateSystem3D slice = geometry.GetProjectionSlice(projection, z);
       OrthancStone::ImageBuffer3D::SliceReader sliceReader(source, projection, static_cast<unsigned int>(z));
 
       SourceReader pixelReader(sliceReader.GetAccessor());
--- a/Framework/Toolbox/ParallelSlices.cpp	Tue May 28 18:09:48 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,215 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 Osimis S.A., 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 <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "ParallelSlices.h"
-
-#include "GeometryToolbox.h"
-#include "../Volumes/ImageBuffer3D.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-namespace OrthancStone
-{
-  ParallelSlices::ParallelSlices()
-  {
-    Clear();
-  }
-
-
-  ParallelSlices::ParallelSlices(const ParallelSlices& other)
-  {
-    normal_ = other.normal_;
-
-    slices_.resize(other.slices_.size());
-
-    for (size_t i = 0; i < slices_.size(); i++)
-    {
-      assert(other.slices_[i] != NULL);
-      slices_[i] = new CoordinateSystem3D(*other.slices_[i]);
-    }
-  }
-
-
-  void ParallelSlices::Clear()
-  {
-    for (size_t i = 0; i < slices_.size(); i++)
-    {
-      if (slices_[i] != NULL)
-      {
-        delete slices_[i];
-        slices_[i] = NULL;
-      }
-    }
-
-    slices_.clear();
-    LinearAlgebra::AssignVector(normal_, 0, 0, 1);
-  }
-  
-
-  ParallelSlices::~ParallelSlices()
-  {
-    Clear();
-  }
-
-
-  void ParallelSlices::AddSlice(const CoordinateSystem3D& slice)
-  {
-    if (slices_.empty())
-    {
-      normal_ = slice.GetNormal();
-      slices_.push_back(new CoordinateSystem3D(slice));
-    }
-    else if (GeometryToolbox::IsParallel(slice.GetNormal(), normal_))
-    {
-      slices_.push_back(new CoordinateSystem3D(slice));
-    }
-    else
-    {
-      LOG(ERROR) << "Trying to add a slice that is not parallel to the previous ones";
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-  }
-
-
-  void ParallelSlices::AddSlice(const Vector& origin,
-                                const Vector& axisX,
-                                const Vector& axisY)
-  {
-    CoordinateSystem3D slice(origin, axisX, axisY);
-    AddSlice(slice);
-  }
-
-
-  const CoordinateSystem3D& ParallelSlices::GetSlice(size_t index) const
-  {
-    if (index >= slices_.size())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-    else
-    {
-      return *slices_[index];
-    }
-  }
-
-
-  bool ParallelSlices::ComputeClosestSlice(size_t& closestSlice,
-                                           double& closestDistance,
-                                           const Vector& origin) const
-  {
-    if (slices_.empty())
-    {
-      return false;
-    }
-
-    double reference = boost::numeric::ublas::inner_prod(origin, normal_);
-
-    closestSlice = 0;
-    closestDistance = std::numeric_limits<double>::infinity();
-
-    for (size_t i = 0; i < slices_.size(); i++)
-    {
-      double distance = fabs(boost::numeric::ublas::inner_prod(slices_[i]->GetOrigin(), normal_) - reference);
-
-      if (distance < closestDistance)
-      {
-        closestSlice = i;
-        closestDistance = distance;
-      }
-    }
-
-    return true;
-  }
-
-
-  ParallelSlices* ParallelSlices::Reverse() const
-  {
-    std::auto_ptr<ParallelSlices> reversed(new ParallelSlices);
-
-    for (size_t i = slices_.size(); i > 0; i--)
-    {
-      const CoordinateSystem3D& slice = *slices_[i - 1];
-
-      reversed->AddSlice(slice.GetOrigin(),
-                         -slice.GetAxisX(),
-                         slice.GetAxisY());
-    }
-
-    return reversed.release();
-  }
-
-
-  ParallelSlices* ParallelSlices::FromVolumeImage(const VolumeImageGeometry& geometry,
-                                                  VolumeProjection projection)
-  {
-    const Vector dimensions = geometry.GetVoxelDimensions(VolumeProjection_Axial);
-    const CoordinateSystem3D& axial = geometry.GetAxialGeometry();
-    
-    std::auto_ptr<ParallelSlices> result(new ParallelSlices);
-
-    switch (projection)
-    {
-      case VolumeProjection_Axial:
-        for (unsigned int z = 0; z < geometry.GetDepth(); z++)
-        {
-          Vector origin = axial.GetOrigin();
-          origin += static_cast<double>(z) * dimensions[2] * axial.GetNormal();
-
-          result->AddSlice(origin,
-                           axial.GetAxisX(),
-                           axial.GetAxisY());
-        }
-        break;
-
-      case VolumeProjection_Coronal:
-        for (unsigned int y = 0; y < geometry.GetHeight(); y++)
-        {
-          Vector origin = axial.GetOrigin();
-          origin += static_cast<double>(y) * dimensions[1] * axial.GetAxisY();
-          origin += static_cast<double>(geometry.GetDepth() - 1) * dimensions[2] * axial.GetNormal();
-
-          result->AddSlice(origin,
-                           axial.GetAxisX(),
-                           -axial.GetNormal());
-        }
-        break;
-
-      case VolumeProjection_Sagittal:
-        for (unsigned int x = 0; x < geometry.GetWidth(); x++)
-        {
-          Vector origin = axial.GetOrigin();
-          origin += static_cast<double>(x) * dimensions[0] * axial.GetAxisX();
-          origin += static_cast<double>(geometry.GetDepth() - 1) * dimensions[2] * axial.GetNormal();
-
-          result->AddSlice(origin,
-                           axial.GetAxisY(),
-                           -axial.GetNormal());
-        }
-        break;
-
-      default:
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    return result.release();
-  }
-}
--- a/Framework/Toolbox/ParallelSlices.h	Tue May 28 18:09:48 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 Osimis S.A., 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 <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "CoordinateSystem3D.h"
-#include "../Volumes/VolumeImageGeometry.h"
-
-namespace OrthancStone
-{
-  class ParallelSlices : public boost::noncopyable
-  {
-  private:
-    Vector                            normal_;
-    std::vector<CoordinateSystem3D*>  slices_;
-    
-    ParallelSlices& operator= (const ParallelSlices& other);  // Forbidden
-
-    void Clear();
-
-  public:
-    ParallelSlices();
-
-    ParallelSlices(const ParallelSlices& other);
-
-    ~ParallelSlices();
-
-    const Vector& GetNormal() const
-    {
-      return normal_;
-    }
-
-    void AddSlice(const CoordinateSystem3D& slice);
-
-    void AddSlice(const Vector& origin,
-                  const Vector& axisX,
-                  const Vector& axisY);
-
-    size_t GetSliceCount() const
-    {
-      return slices_.size();
-    }
-
-    const CoordinateSystem3D& GetSlice(size_t index) const;
-
-    bool ComputeClosestSlice(size_t& closestSlice,
-                             double& closestDistance,
-                             const Vector& origin) const;
-
-    ParallelSlices* Reverse() const;
-
-    static ParallelSlices* FromVolumeImage(const VolumeImageGeometry& geometry,
-                                           VolumeProjection projection);
-  };
-}
--- a/Framework/Toolbox/ParallelSlicesCursor.cpp	Tue May 28 18:09:48 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,221 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 Osimis S.A., 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 <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "ParallelSlicesCursor.h"
-
-#include <Core/OrthancException.h>
-
-namespace OrthancStone
-{
-  size_t ParallelSlicesCursor::GetDefaultSlice()
-  {
-    if (slices_.get() == NULL)
-    {
-      return 0;
-    }
-    else
-    {
-      return slices_->GetSliceCount() / 2;
-    }
-  }
-
-
-  size_t ParallelSlicesCursor::GetSliceCount()
-  {
-    if (slices_.get() == NULL)
-    {
-      return 0;
-    }
-    else
-    {
-      return slices_->GetSliceCount();
-    }
-  }
-
-
-  CoordinateSystem3D ParallelSlicesCursor::GetSlice(size_t slice)
-  {
-    if (slices_.get() == NULL)
-    {
-      return CoordinateSystem3D();
-    }
-    else
-    {
-      return slices_->GetSlice(slice);
-    }
-  }
-
-
-  void ParallelSlicesCursor::SetGeometry(const ParallelSlices& slices)
-  {
-    slices_.reset(new ParallelSlices(slices));
-
-    currentSlice_ = GetDefaultSlice();
-  }
-
-
-  CoordinateSystem3D ParallelSlicesCursor::GetCurrentSlice()
-  {
-    if (slices_.get() != NULL &&
-        currentSlice_ < slices_->GetSliceCount())
-    {
-      return slices_->GetSlice(currentSlice_);
-    }
-    else
-    {
-      return CoordinateSystem3D();  // No slice is available, return the canonical geometry
-    }
-  }
-
-
-  bool ParallelSlicesCursor::SetDefaultSlice()
-  {
-    size_t slice = GetDefaultSlice();
-
-    if (currentSlice_ != slice)
-    {
-      currentSlice_ = slice;
-      return true;
-    }
-    else
-    {
-      return false;
-    }
-  }
-
-
-  bool ParallelSlicesCursor::ApplyOffset(SliceOffsetMode mode,
-                                         int offset)
-  {
-    if (slices_.get() == NULL)
-    {
-      return false;
-    }
-
-    int count = static_cast<int>(slices_->GetSliceCount());
-    if (count == 0)
-    {
-      return false;
-    }
-
-    int slice;
-    if (static_cast<int>(currentSlice_) >= count)
-    {
-      slice = count - 1;
-    }
-    else
-    {
-      slice = static_cast<int>(currentSlice_);
-    }
-
-    switch (mode)
-    {
-      case SliceOffsetMode_Absolute:
-      {
-        slice = offset;
-        break;
-      }
-
-      case SliceOffsetMode_Relative:
-      {
-        slice += offset;
-        break;
-      }
-
-      case SliceOffsetMode_Loop:
-      {
-        slice += offset;
-        while (slice < 0)
-        {
-          slice += count;
-        }
-
-        while (slice >= count)
-        {
-          slice -= count;
-        }
-
-        break;
-      }
-
-      default:
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    if (slice < 0)
-    {
-      slice = 0;
-    }
-
-    if (slice >= count)
-    {
-      slice = count - 1;
-    }
-
-    if (slice != static_cast<int>(currentSlice_))
-    {
-      currentSlice_ = static_cast<int>(slice);
-      return true;
-    }
-    else
-    {
-      return false;
-    }
-  }
-
-
-  bool ParallelSlicesCursor::ApplyWheelEvent(MouseWheelDirection direction,
-                                             KeyboardModifiers modifiers)
-  {
-    int offset = (modifiers & KeyboardModifiers_Control ? 10 : 1);
-
-    switch (direction)
-    {
-      case MouseWheelDirection_Down:
-        return ApplyOffset(SliceOffsetMode_Relative, -offset);
-
-      case MouseWheelDirection_Up:
-        return ApplyOffset(SliceOffsetMode_Relative, offset);
-
-      default:
-        return false;
-    }
-  }
-
-
-  bool ParallelSlicesCursor::LookupSliceContainingPoint(const Vector& p)
-  {
-    size_t slice;
-    double distance;
-
-    if (slices_.get() != NULL &&
-        slices_->ComputeClosestSlice(slice, distance, p))
-    {
-      if (currentSlice_ != slice)
-      {
-        currentSlice_ = slice;
-        return true;
-      }
-    }
-
-    return false;
-  }
-}
--- a/Framework/Toolbox/ParallelSlicesCursor.h	Tue May 28 18:09:48 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 Osimis S.A., 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 <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "ParallelSlices.h"
-#include "../StoneEnumerations.h"
-
-namespace OrthancStone
-{
-  class ParallelSlicesCursor : public boost::noncopyable
-  {
-  private:
-    std::auto_ptr<ParallelSlices>  slices_;
-    size_t                         currentSlice_;
-
-    size_t GetDefaultSlice();
-
-  public:
-    ParallelSlicesCursor() :
-      currentSlice_(0)
-    {
-    }
-
-    void SetGeometry(const ParallelSlices& slices);
-
-    size_t GetSliceCount();
-
-    CoordinateSystem3D GetSlice(size_t slice);
-
-    CoordinateSystem3D GetCurrentSlice();
-
-    // Returns "true" iff. the slice has actually changed
-    bool SetDefaultSlice();
-
-    // Returns "true" iff. the slice has actually changed
-    bool ApplyOffset(SliceOffsetMode mode,
-                     int offset);
-
-    // Returns "true" iff. the slice has actually changed
-    bool ApplyWheelEvent(MouseWheelDirection direction,
-                         KeyboardModifiers modifiers);
-
-    // Returns "true" iff. the slice has actually changed
-    bool LookupSliceContainingPoint(const Vector& p);
-  };
-}
--- a/Framework/Volumes/VolumeImageGeometry.cpp	Tue May 28 18:09:48 2019 +0200
+++ b/Framework/Volumes/VolumeImageGeometry.cpp	Tue May 28 18:21:00 2019 +0200
@@ -309,9 +309,9 @@
 
 
   CoordinateSystem3D VolumeImageGeometry::GetProjectionSlice(VolumeProjection projection,
-                                                             unsigned int depth) const
+                                                             unsigned int z) const
   {
-    if (depth >= GetProjectionDepth(projection))
+    if (z >= GetProjectionDepth(projection))
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
@@ -319,7 +319,7 @@
     Vector dim = GetVoxelDimensions(projection);
     CoordinateSystem3D plane = GetProjectionGeometry(projection);
 
-    plane.SetOrigin(plane.GetOrigin() + static_cast<double>(depth) * plane.GetNormal() * dim[2]);
+    plane.SetOrigin(plane.GetOrigin() + static_cast<double>(z) * plane.GetNormal() * dim[2]);
 
     return plane;
   }
--- a/Framework/Volumes/VolumeImageGeometry.h	Tue May 28 18:09:48 2019 +0200
+++ b/Framework/Volumes/VolumeImageGeometry.h	Tue May 28 18:21:00 2019 +0200
@@ -129,6 +129,6 @@
                      const CoordinateSystem3D& plane) const;
 
     CoordinateSystem3D GetProjectionSlice(VolumeProjection projection,
-                                          unsigned int depth) const;
+                                          unsigned int z) const;
   };
 }
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Tue May 28 18:09:48 2019 +0200
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Tue May 28 18:21:00 2019 +0200
@@ -338,6 +338,8 @@
     ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/MessagingToolbox.cpp
     ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/OrthancApiClient.cpp
     ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp
+    ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/ParallelSlices.cpp
+    ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/ParallelSlicesCursor.cpp
     ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/Slice.cpp
     ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/ViewportGeometry.cpp
     ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Viewport/IMouseTracker.h
@@ -484,8 +486,6 @@
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/GeometryToolbox.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ImageGeometry.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/LinearAlgebra.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ParallelSlices.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ParallelSlicesCursor.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ShearWarpProjectiveTransform.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/SlicesSorter.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/UndoRedoStack.cpp