From dda4b115608c14a24ab90da405638f0be7444dee Mon Sep 17 00:00:00 2001
From: Emmanuel Christophe <emmanuel.christophe@orfeo-toolbox.org>
Date: Wed, 24 Mar 2010 13:28:25 +0800
Subject: [PATCH] ENH: make the ImageRegionTileMapSplitter multidimensional

---
 Code/Common/otbImageRegionTileMapSplitter.h   |  21 +--
 Code/Common/otbImageRegionTileMapSplitter.txx | 124 ++++++++++--------
 Testing/Code/Common/CMakeLists.txt            |   6 +-
 .../Common/otbImageRegionTileMapSplitter.cxx  | 120 ++++++++++++++---
 4 files changed, 182 insertions(+), 89 deletions(-)

diff --git a/Code/Common/otbImageRegionTileMapSplitter.h b/Code/Common/otbImageRegionTileMapSplitter.h
index 537421fe27..70870c060c 100644
--- a/Code/Common/otbImageRegionTileMapSplitter.h
+++ b/Code/Common/otbImageRegionTileMapSplitter.h
@@ -73,10 +73,10 @@ class ITK_EXPORT ImageRegionTileMapSplitter: public itk::ImageRegionSplitter<VIm
 {
 public:
   /** Standard class typedefs. */
-  typedef ImageRegionTileMapSplitter              Self;
-  typedef itk::ImageRegionSplitter<VImageDimension>  Superclass;
-  typedef itk::SmartPointer<Self>  Pointer;
-  typedef itk::SmartPointer<const Self>  ConstPointer;
+  typedef ImageRegionTileMapSplitter                Self;
+  typedef itk::ImageRegionSplitter<VImageDimension> Superclass;
+  typedef itk::SmartPointer<Self>                   Pointer;
+  typedef itk::SmartPointer<const Self>             ConstPointer;
 
   /** Method for creation through the object factory. */
   itkNewMacro(Self);
@@ -94,12 +94,12 @@ public:
   }
 
   /** Index typedef support. An index is used to access pixel values. */
-  typedef itk::Index<VImageDimension>  IndexType;
-  typedef typename IndexType::IndexValueType  IndexValueType;
+  typedef itk::Index<VImageDimension>        IndexType;
+  typedef typename IndexType::IndexValueType IndexValueType;
 
   /** Size typedef support. A size is used to define region bounds. */
-  typedef itk::Size<VImageDimension>  SizeType;
-  typedef typename SizeType::SizeValueType  SizeValueType;
+  typedef itk::Size<VImageDimension>       SizeType;
+  typedef typename SizeType::SizeValueType SizeValueType;
 
   /** Region typedef support.   */
   typedef itk::ImageRegion<VImageDimension> RegionType;
@@ -120,7 +120,7 @@ public:
                               const RegionType &region);
 
 protected:
-  ImageRegionTileMapSplitter() {}
+  ImageRegionTileMapSplitter(): m_AlignStep(256){}
   virtual ~ImageRegionTileMapSplitter() {}
   void PrintSelf(std::ostream& os, itk::Indent indent) const;
 
@@ -128,6 +128,8 @@ private:
   ImageRegionTileMapSplitter(const ImageRegionTileMapSplitter&); //purposely not implemented
   void operator=(const ImageRegionTileMapSplitter&); //purposely not implemented
 
+  unsigned int m_SplitsPerDimension[VImageDimension];
+  unsigned int m_AlignStep;
 };
 
 
@@ -138,4 +140,3 @@ private:
 #endif
 
 #endif
-
diff --git a/Code/Common/otbImageRegionTileMapSplitter.txx b/Code/Common/otbImageRegionTileMapSplitter.txx
index e7ff7dc9bc..71a7737460 100644
--- a/Code/Common/otbImageRegionTileMapSplitter.txx
+++ b/Code/Common/otbImageRegionTileMapSplitter.txx
@@ -1,4 +1,3 @@
-
 /*=========================================================================
 
   Program:   ORFEO Toolbox
@@ -21,6 +20,7 @@
 
 #include "otbImageRegionTileMapSplitter.h"
 #include "otbMath.h"
+#include "otbMacro.h"
 
 namespace otb
 {
@@ -35,25 +35,40 @@ ImageRegionTileMapSplitter<VImageDimension>
 {
   int splitAxis;
   const SizeType &regionSize = region.GetSize();
+  const IndexType &regionIndex = region.GetIndex();
+
+  // requested number of splits per dimension
+  unsigned int numPieces = 1;
 
   // split on the outermost dimension available
   splitAxis = VImageDimension - 1;
-  while (regionSize[splitAxis] == 1)
-  {
-    --splitAxis;
-    if (splitAxis < 0)
-    { // cannot split
-      itkDebugMacro("  Cannot Split");
-      return 1;
-    }
-  }
 
   // determine the actual number of pieces that will be generated
-  SizeValueType range = regionSize[splitAxis];
-  int valuesPerPiece = static_cast<int>(vcl_ceil(static_cast<double>(range/((double)requestedNumber*256)) ) ) * 256;
-  int maxPieceUsed = static_cast<int>(vcl_ceil(static_cast<double>(range/(double)valuesPerPiece)));
-
-  return maxPieceUsed + 1;
+  for (unsigned int j = VImageDimension; j > 0; --j)
+    {
+//    otbMsgDevMacro(<< "*** Dimension: " << j-1);
+    SizeValueType range = regionSize[j - 1];
+    unsigned long int remainingToDo = vcl_ceil((double) requestedNumber / numPieces);
+//    unsigned long int remainingToDo = requestedNumber - numPieces;
+    unsigned int maxPieces = (regionIndex[j - 1] + regionSize[j - 1] - 1) / m_AlignStep - regionIndex[j - 1]
+        / m_AlignStep + 1;
+    unsigned int stepPerPiece = 1;
+    if (remainingToDo < maxPieces)
+      {
+      stepPerPiece = static_cast<int> (vcl_floor(static_cast<double> (maxPieces) / remainingToDo));
+      if ((remainingToDo-1)*(stepPerPiece+1) < maxPieces )
+        {
+        stepPerPiece += 1;
+        }
+      }
+    unsigned int maxPieceUsed = static_cast<int> (vcl_ceil(static_cast<double> (maxPieces / (double) stepPerPiece)));
+    m_SplitsPerDimension[j - 1] = maxPieceUsed;
+//    otbMsgDevMacro("*** maxPieces stepPerPiece maxPieceUsed " << maxPieces
+//                      << " " << stepPerPiece << " " << maxPieceUsed);
+    numPieces *= maxPieceUsed;
+    }
+//  otbMsgDevMacro("*** numPieces " << numPieces);
+  return numPieces;
 }
 
 
@@ -67,7 +82,7 @@ ImageRegionTileMapSplitter<VImageDimension>
 {
   int splitAxis;
   RegionType splitRegion;
-  IndexType splitIndex;
+  IndexType splitIndex, regionIndex;
   SizeType splitSize, regionSize;
 
   // Initialize the splitRegion to the requested region
@@ -76,50 +91,49 @@ ImageRegionTileMapSplitter<VImageDimension>
   splitSize = splitRegion.GetSize();
 
   regionSize = region.GetSize();
+  regionIndex = region.GetIndex();
 
-  // split on the outermost dimension available
-  splitAxis = VImageDimension - 1;
-  while (regionSize[splitAxis] == 1)
-  {
-    --splitAxis;
-    if (splitAxis < 0)
-    { // cannot split
-      itkDebugMacro("  Cannot Split");
-      return splitRegion;
+  unsigned int numPieces = GetNumberOfSplits(region, numberOfPieces);
+  if (i > numPieces)
+    {
+    itkDebugMacro("  Cannot Split");
+    return splitRegion;
     }
-  }
-
-  // determine the actual number of pieces that will be generated
-  SizeValueType range = regionSize[splitAxis];
-  int valuesPerPiece = static_cast<int>((int)vcl_ceil(static_cast<double>(range/((double)numberOfPieces*256)))) * 256;
-  int maxPieceUsed = static_cast<int>(vcl_ceil(static_cast<double>(range/(double)valuesPerPiece)));
-
-  // Split the region
-  if ((int) i == maxPieceUsed-1)
-  {
-    splitIndex[splitAxis] += i*valuesPerPiece;
-    // last piece needs to process the "rest" dimension being split
-//     splitSize[splitAxis] = splitSize[splitAxis] - i*valuesPerPiece;
-    splitSize[splitAxis] = regionSize[splitAxis] - splitIndex[splitAxis];
-  }
-  if (((int) i == 0) && ((int) i != maxPieceUsed-1))
-  {
-    //First piece may not contain a whole piece
-    //splitIndex stay at splitRegion.GetIndex();
-    splitSize[splitAxis] = ((static_cast<int>(vcl_floor(static_cast<double>(splitIndex[splitAxis]/valuesPerPiece))))+1)
-                           *valuesPerPiece - splitIndex[splitAxis];
-  }
-  if ((int) i < maxPieceUsed-1)
-  {
-    splitIndex[splitAxis] += i*valuesPerPiece;
-    splitSize[splitAxis] = valuesPerPiece;
-  }
 
+  unsigned int stackSize = 1;
+  for (unsigned int j = 0; j < VImageDimension; ++j)
+    {
+    unsigned int slicePos = (i % (stackSize * m_SplitsPerDimension[j])) / stackSize;
+    stackSize *= m_SplitsPerDimension[j];
+
+    unsigned int generalSplitSize = vcl_ceil(static_cast<double> (regionSize[j]) / (m_SplitsPerDimension[j]
+        * m_AlignStep)) * m_AlignStep;//FIXME check
+    if (slicePos == 0)
+      {
+      splitIndex[j] = regionIndex[j];
+      }
+    else
+      {
+      splitIndex[j] = (regionIndex[j] / generalSplitSize + slicePos) * generalSplitSize;
+      }
+    if (slicePos == 0)
+      {
+      splitSize[j] = generalSplitSize - (regionIndex[j] % generalSplitSize);
+      }
+    else if (slicePos == m_SplitsPerDimension[j] - 1)
+      {
+      splitSize[j] = regionSize[j] - (generalSplitSize - (regionIndex[j] % generalSplitSize))
+          - (m_SplitsPerDimension[j] - 2) * generalSplitSize;
+      }
+    else
+      {
+      splitSize[j] = generalSplitSize;
+      }
+    }
 
   // set the split region ivars
-  splitRegion.SetIndex( splitIndex );
-  splitRegion.SetSize( splitSize );
-
+  splitRegion.SetIndex(splitIndex);
+  splitRegion.SetSize(splitSize);
 
   itkDebugMacro("  Split Piece: " << splitRegion );
 
diff --git a/Testing/Code/Common/CMakeLists.txt b/Testing/Code/Common/CMakeLists.txt
index dca93167a5..0b2bfd8bef 100644
--- a/Testing/Code/Common/CMakeLists.txt
+++ b/Testing/Code/Common/CMakeLists.txt
@@ -723,11 +723,7 @@ ADD_TEST(coTvImageRegionTileMapSplitter ${COMMON_TESTS8}
         ${BASELINE_FILES}/coImageRegionTileMapSplitter.txt
                 ${TEMP}/coImageRegionTileMapSplitter.txt
     otbImageRegionTileMapSplitter
-    45 45      # Index
-    1000 1500  # Size
-    10         # Nb split
-    2          # Number of slipt
-    ${TEMP}/coImageRegionTileMapSplitter.txt
+        ${TEMP}/coImageRegionTileMapSplitter.txt
 )
 
 # -------------  otb::ImageOfVectorsToMonoChannelExtractROI ----------------------------
diff --git a/Testing/Code/Common/otbImageRegionTileMapSplitter.cxx b/Testing/Code/Common/otbImageRegionTileMapSplitter.cxx
index 4cc19ac8f6..ef069b72c9 100644
--- a/Testing/Code/Common/otbImageRegionTileMapSplitter.cxx
+++ b/Testing/Code/Common/otbImageRegionTileMapSplitter.cxx
@@ -20,46 +20,128 @@
 
 int otbImageRegionTileMapSplitter( int argc, char * argv[] )
 {
+
+
   const int Dimension = 2;
-  typedef otb::ImageRegionTileMapSplitter< Dimension >  FilterType;
-  typedef FilterType::IndexType IndexType;
-  typedef FilterType::SizeType SizeType;
-  typedef FilterType::RegionType RegionType;
+  typedef otb::ImageRegionTileMapSplitter< Dimension > FilterType;
+  typedef FilterType::IndexType                        IndexType;
+  typedef FilterType::SizeType                         SizeType;
+  typedef FilterType::RegionType                       RegionType;
+
+  std::ofstream outfile(argv[1]);
+  FilterType::Pointer filter = FilterType::New();
 
+  RegionType region, region2;
+  unsigned int nb, nbSplitTheoric, nbAsked;
   IndexType index;
-  index[0] = atoi(argv[1]);
-  index[1] = atoi(argv[2]);
   SizeType size;
-  size[0] = atoi(argv[3]);
-  size[1] = atoi(argv[4]);
-  unsigned int nbSplitTheoric(atoi(argv[5]));
-  unsigned int nbAsked(atoi(argv[6]));
-  const char * outfname(argv[7]);
 
+  //Case 1
+  index[0] = 45;
+  index[1] = 45;
+  size[0] = 1000;
+  size[1] = 1500;
+  nbSplitTheoric = 10;
+  nbAsked = 2;
 
-  RegionType region;
+  region.SetSize(size);
+  region.SetIndex(index);
+
+  nb = filter->GetNumberOfSplits(region,nbSplitTheoric);
+  region2 = filter->GetSplit(nbAsked,nb,region);
+
+  outfile << "\nCase 1 \n";
+  outfile << "Input region: "<<region<<std::endl;
+  outfile << "Input NumberOfSplits: "<<nbSplitTheoric<<std::endl;
+  outfile << "Output GetNumberOfSplits: "<<nb<<std::endl;
+  outfile << "Output GetSplit("<<nbAsked<<","<<nb<<",input region): "<<std::endl;
+  outfile << "Output region: "<< region2<<std::endl;
+
+  //Case 2
+  index[0] = 45;
+  index[1] = 45;
+  size[0] = 1048576;
+  size[1] = 1048576;
+  nbSplitTheoric = 16777216;
+  nbAsked = 2;
 
   region.SetSize(size);
   region.SetIndex(index);
 
-  FilterType::Pointer filter = FilterType::New();
+  nb = filter->GetNumberOfSplits(region,nbSplitTheoric);
+  region2 = filter->GetSplit(nbAsked,nb,region);
+
+  outfile << "\nCase 2 \n";
+  outfile << "Input region: "<<region<<std::endl;
+  outfile << "Input NumberOfSplits: "<<nbSplitTheoric<<std::endl;
+  outfile << "Output GetNumberOfSplits: "<<nb<<std::endl;
+  outfile << "Output GetSplit("<<nbAsked<<","<<nb<<",input region): "<<std::endl;
+  outfile << "Output region: "<< region2<<std::endl;
+
+  //Case 3
+  index[0] = 45;
+  index[1] = 45;
+  size[0] = 1048576;
+  size[1] = 1048576;
+  nbSplitTheoric = 23;
+  nbAsked = 4;
+
+  region.SetSize(size);
+  region.SetIndex(index);
+
+  nb = filter->GetNumberOfSplits(region,nbSplitTheoric);
+  region2 = filter->GetSplit(nbAsked,nb,region);
 
-  unsigned int nb = filter->GetNumberOfSplits(region,nbSplitTheoric);
+  outfile << "\nCase 3 \n";
+  outfile << "Input region: "<<region<<std::endl;
+  outfile << "Input NumberOfSplits: "<<nbSplitTheoric<<std::endl;
+  outfile << "Output GetNumberOfSplits: "<<nb<<std::endl;
+  outfile << "Output GetSplit("<<nbAsked<<","<<nb<<",input region): "<<std::endl;
+  outfile << "Output region: "<< region2<<std::endl;
   
-  RegionType region2 = filter->GetSplit(nbAsked,nb,region);
+  //Case 4
+  index[0] = 45;
+  index[1] = 45;
+  size[0] = 1048576;
+  size[1] = 1024;
+  nbSplitTheoric = 16777216;
+  nbAsked = 16387;
 
-  std::ofstream outfile(outfname);
+  region.SetSize(size);
+  region.SetIndex(index);
 
+  nb = filter->GetNumberOfSplits(region,nbSplitTheoric);
+  region2 = filter->GetSplit(nbAsked,nb,region);
 
+  outfile << "\nCase 4 \n";
   outfile << "Input region: "<<region<<std::endl;
   outfile << "Input NumberOfSplits: "<<nbSplitTheoric<<std::endl;
   outfile << "Output GetNumberOfSplits: "<<nb<<std::endl;
   outfile << "Output GetSplit("<<nbAsked<<","<<nb<<",input region): "<<std::endl;
-  outfile << "    "<<region2<<std::endl;
+  outfile << "Output region: "<< region2<<std::endl;
+
+  //Case 5
+  index[0] = 0;
+  index[1] = 0;
+  size[0] = 513;
+  size[1] = 5376;
+  nbSplitTheoric = 8;
+  nbAsked = 9;
+
+  region.SetSize(size);
+  region.SetIndex(index);
+
+  nb = filter->GetNumberOfSplits(region,nbSplitTheoric);
+  region2 = filter->GetSplit(nbAsked,nb,region);
+
+  outfile << "\nCase 5 \n";
+  outfile << "Input region: "<<region<<std::endl;
+  outfile << "Input NumberOfSplits: "<<nbSplitTheoric<<std::endl;
+  outfile << "Output GetNumberOfSplits: "<<nb<<std::endl;
+  outfile << "Output GetSplit("<<nbAsked<<","<<nb<<",input region): "<<std::endl;
+  outfile << "Output region: "<< region2<<std::endl;
 
   outfile.close();
 
   return EXIT_SUCCESS;
 }
-
-
-- 
GitLab