From 0563c6f105608fcc45a88e721e372a333bb0ffa7 Mon Sep 17 00:00:00 2001
From: Owen Arnold <owen.arnold@stfc.ac.uk>
Date: Fri, 7 Mar 2014 16:56:29 +0000
Subject: [PATCH] refs #9155. Start applying neighbour finding to iterator.

---
 .../inc/MantidCrystal/DisjointElement.h       |  3 +-
 .../Framework/Crystal/src/DisjointElement.cpp | 10 ++++
 .../Framework/Kernel/inc/MantidKernel/Utils.h | 26 +++++++++
 .../MantidMDEvents/MDHistoWorkspaceIterator.h |  6 +-
 .../MDEvents/src/MDHistoWorkspaceIterator.cpp | 57 +++++++++++++++++++
 .../test/MDHistoWorkspaceIteratorTest.h       | 22 +++++++
 6 files changed, 121 insertions(+), 3 deletions(-)

diff --git a/Code/Mantid/Framework/Crystal/inc/MantidCrystal/DisjointElement.h b/Code/Mantid/Framework/Crystal/inc/MantidCrystal/DisjointElement.h
index e92895b5e22..d6e0e417302 100644
--- a/Code/Mantid/Framework/Crystal/inc/MantidCrystal/DisjointElement.h
+++ b/Code/Mantid/Framework/Crystal/inc/MantidCrystal/DisjointElement.h
@@ -68,8 +68,7 @@ namespace Crystal
     
   };
 
-
-
+  void unionElements(DisjointElement* a, DisjointElement* b);
 
 } // namespace Crystal
 } // namespace Mantid
diff --git a/Code/Mantid/Framework/Crystal/src/DisjointElement.cpp b/Code/Mantid/Framework/Crystal/src/DisjointElement.cpp
index 098a9151646..a836bca11a0 100644
--- a/Code/Mantid/Framework/Crystal/src/DisjointElement.cpp
+++ b/Code/Mantid/Framework/Crystal/src/DisjointElement.cpp
@@ -148,5 +148,15 @@ namespace Mantid
 
     }
 
+    /**
+     * Convenience non-member function.
+     * @param a : Pointer to first disjoint element to join
+     * @param b : Pointer to second disjoint element to join
+     */
+    void unionElements(DisjointElement* a, DisjointElement* b)
+    {
+      a->unionWith(b);
+    }
+
   } // namespace Crystal
 } // namespace Mantid
diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/Utils.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/Utils.h
index 005ece79d82..7c6aedff8c8 100644
--- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/Utils.h
+++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/Utils.h
@@ -255,6 +255,32 @@ namespace Utils
 
   }
 
+  /**
+   * Determine, using an any-vertex touching type approach, whether the neighbour linear index corresponds to a true neighbour of the subject, which is already
+   * decomposed into it's constituent dimension indices. subject is already expressed in it's constituent indices for speed.
+   *
+   * The approach used here is to determine if a dimension index differ by any more than 1 in any dimension. If it does, then the neighbour does not represent
+   * a valid neighbour of the subject.
+   * @param ndims
+   * @param neighbour_linear_index
+   * @param subject_indices
+   * @param num_bins
+   * @return True if the are neighbours, otherwise false.
+   */
+  inline bool isNeighbourOfSubject(const size_t ndims, const size_t neighbour_linear_index, const size_t* subject_indices, const size_t * num_bins, const size_t * index_max)
+  {
+    size_t neighbour_indices[ndims];
+    Utils::NestedForLoop::GetIndicesFromLinearIndex(ndims, neighbour_linear_index, num_bins, index_max, neighbour_indices);
+    for(size_t ind = 0; ind < ndims; ++ind)
+    {
+      auto diff = std::abs(static_cast<int>(subject_indices[ind] - neighbour_indices[ind]));
+      if (diff > 1)
+      {
+        return false;
+      }
+    }
+    return true;
+  }
 
 
 } // namespace Utils
diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspaceIterator.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspaceIterator.h
index 94e52403ef8..f9b1b291c0e 100644
--- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspaceIterator.h
+++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspaceIterator.h
@@ -96,6 +96,8 @@ namespace MDEvents
 
     size_t getLinearIndex() const;
 
+    std::vector<size_t> findNeighbourIndexes() const;
+
   protected:
     /// The MDHistoWorkspace being iterated.
     const MDHistoWorkspace * m_ws;
@@ -133,9 +135,11 @@ namespace MDEvents
     /// Array to find indices from linear indices
     size_t * m_indexMaker;
 
+    /// Neighbour finding permutations.
+    mutable std::vector<long> m_permutations;
+
     /// Skipping policy.
     SkippingPolicy_scptr m_skippingPolicy;
-
   };
 
 
diff --git a/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspaceIterator.cpp b/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspaceIterator.cpp
index 02e037593d1..cd8220bd791 100644
--- a/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspaceIterator.cpp
+++ b/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspaceIterator.cpp
@@ -137,6 +137,14 @@ namespace MDEvents
       if (!m_function->isPointContained(m_center))
         next();
     }
+
+    const size_t neighbourSpan = 3;
+    size_t totalNeighbours = neighbourSpan;
+    for (size_t i = 1; i < m_nd; i++)
+    {
+      totalNeighbours = totalNeighbours * neighbourSpan;
+    }
+    m_permutations.resize(totalNeighbours);
   }
     
   //----------------------------------------------------------------------------------------------
@@ -365,6 +373,55 @@ namespace MDEvents
     return m_pos;
   }
 
+  /**
+   * Gets indexes of bins/pixels/boxes neighbouring the present iterator location.
+   * The number of neighbour indexes returned will depend upon the dimensionality of the workspace as well as the presence
+   * of boundaries and edges.
+   * @return vector of linear indexes to neighbour locations.
+   */
+  std::vector<size_t> MDHistoWorkspaceIterator::findNeighbourIndexes() const
+  {
+
+    Utils::NestedForLoop::GetIndicesFromLinearIndex(m_nd, m_pos, m_indexMaker, m_indexMax,
+            m_index);
+
+    size_t offset = 1;
+    const int base = 3;
+
+    m_permutations[0] = 0;
+    m_permutations[1] = 1;
+    m_permutations[2] = -1;
+    size_t n_permutations = 3;
+
+    for(size_t j = 0; j < m_nd; ++j)
+    {
+      offset = offset * m_indexMaker[j-1];
+
+      for(size_t k = 0; k < m_permutations.size(); ++k)
+      {
+        long newVariant = m_permutations[k] + long(offset);
+        m_permutations[j] = newVariant;
+        m_permutations[j+1] = -newVariant;
+        n_permutations += 2;
+      }
+    }
+
+    std::vector<size_t> neighbourIndexes;
+    for(size_t i = 0; i < n_permutations; ++i)
+    {
+      if (m_permutations[i] == 0)
+      {
+        continue;
+      }
+      size_t neighbour_index = m_pos + m_permutations[i];
+      if( Utils::isNeighbourOfSubject(m_nd, neighbour_index, m_index, m_indexMaker, m_indexMax ) )
+      {
+        neighbourIndexes.push_back(neighbour_index);
+      }
+    }
+    return neighbourIndexes;
+  }
+
 } // namespace Mantid
 } // namespace MDEvents
 
diff --git a/Code/Mantid/Framework/MDEvents/test/MDHistoWorkspaceIteratorTest.h b/Code/Mantid/Framework/MDEvents/test/MDHistoWorkspaceIteratorTest.h
index d9e3e8b5ef1..c6dac263787 100644
--- a/Code/Mantid/Framework/MDEvents/test/MDHistoWorkspaceIteratorTest.h
+++ b/Code/Mantid/Framework/MDEvents/test/MDHistoWorkspaceIteratorTest.h
@@ -247,6 +247,28 @@ public:
     TSM_ASSERT_EQUALS("The first index hit should be 2 since that is the first unmasked one", 5, histoIt->getLinearIndex());
   }
 
+  void test_neighours_1d()
+  {
+    const size_t nd = 1;
+    MDHistoWorkspace_sptr ws = MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, nd, 10);
+
+    MDHistoWorkspaceIterator * it = new MDHistoWorkspaceIterator(ws);
+
+    // At first position
+    std::vector<size_t> neighbourIndexes = it->findNeighbourIndexes();
+    TS_ASSERT_EQUALS(1, neighbourIndexes.size()); // should be on edge
+
+    // Go to intermediate position
+    it->next();
+    neighbourIndexes = it->findNeighbourIndexes();
+    TS_ASSERT_EQUALS(2, neighbourIndexes.size()); // should be on edge
+
+    // Go to last position
+    it->jumpTo(10);
+    neighbourIndexes = it->findNeighbourIndexes();
+    TS_ASSERT_EQUALS(1, neighbourIndexes.size()); // should be on edge
+  }
+
 };
 
 
-- 
GitLab