/*
    GNU Octave level-set package.
    Copyright (C) 2014  Daniel Kraft <d@domob.eu>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* Template implementations of FastMarching.hpp.  */

namespace fastMarching
{

/* ************************************************************************** */
/* Full grid.  */

/**
 * Internal routine used for iterate(), that is called recursively
 * to perform the required number of nested loops.
 * @param cur Current index tuple, will be built up recursively.
 * @param depth Current depth in the recursion.
 * @param f The call-back to call for each cell index.
 */
template<typename F>
  void
  Grid::iterate (IndexTuple& cur, dimensionT depth, const F& f) const
{
  const dimensionT D = size.size ();

  assert (depth <= D);
  if (depth == D)
    {
      f (cur);
      return;
    }

  for (indexT i = 0; i < size[depth]; ++i)
    {
      cur[depth] = i;
      iterate (cur, depth + 1, f);
    }
}

/**
 * Iterate over all neighbours of a given index.  For each neighbour that
 * is still on the grid, call the provided function with its index,
 * the dimension index along which they are neighbours, and the
 * offset along this dimension (+1 or -1).
 * @param c The centre coordinate.
 * @param f The call-back to call for each neighbour.
 */
template<typename F>
  void
  Grid::iterateNeighbours (const IndexTuple& c, const F& f) const
{
  IndexTuple neighbour = c;
  for (dimensionT d = 0; d < neighbour.size (); ++d)
    {
      const auto oldValue = neighbour[d];
      for (neighbour[d] -= 1; neighbour[d] <= oldValue + 2;
           neighbour[d] += 2)
        {
          if (lineariseIndex (neighbour) >= 0)
            f (neighbour, d, neighbour[d] - oldValue);
        }
      neighbour[d] = oldValue;
    }
}

/* ************************************************************************** */

} // Namespace fastMarching.
