/*
    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/>.
*/

#include "Utils.hpp"

#include <octave/lo-ieee.h>

#include <algorithm>
#include <cstdarg>

using namespace fastMarching;

namespace fastMarching
{

/* Provice an Octave-based implementation of issueWarning here.  */
void
issueWarning (const std::string& id, const std::string& fmt, ...)
{
  va_list args;
  va_start (args, fmt);
  vwarning_with_id (id.c_str (), fmt.c_str (), args);
  va_end (args);
}

} // namespace fastMarching

/**
 * Convert an IndexTuple to an index suitable to Octave as the
 * used type Array<octave_idx_type>.
 * @param ind IndexTuple representing the coordinate.
 * @return The same index suitable for Octave.
 */
Array<octave_idx_type>
getOctaveIdx (const fastMarching::IndexTuple& ind)
{
  const dimensionT D = ind.size ();

  Array<octave_idx_type> idx(dim_vector (D, 1));
  std::copy (ind.begin (), ind.end (), idx.fortran_vec ());

  return idx;
}

/**
 * Given two phi values with differing signs, calculate the approximate
 * fraction along the edge connecting both where the zero lies.  This
 * function in particular also handles infinities well.
 * @param my Phi value at the "current point" (corresponding to fraction 0).
 * @param other Other phi value, correspondig to fraction 1.
 * @return Fraction of the zero level-set intersection.
 */
double
getZeroFraction (double my, double other)
{
  const bool myInf = lo_ieee_isinf (my);
  const bool otherInf = lo_ieee_isinf (other);

  if (myInf && otherInf)
    return 0.5;
  if (myInf)
    return 1;
  if (otherInf)
    return 0;

  return std::abs (my / (my - other));
}
