##  Copyright (C) 2014  Daniel Kraft <d@domob.eu>
##  GNU Octave level-set package.
##
##  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/>.

## -*- texinfo -*-
## @deftypefn  {Function File} {@var{phi} =} ls_normalise (@var{phi}, @var{h} = 1, @var{zerotol} = 1e-3)
##
## Normalise the level-set function @var{phi}.  This gets rid of values that
## are exactly zero, by ensuring that each entry of the changed level-set
## function has a magnitude of at least @var{h} * @var{zerotol}.  The
## actual level-set geometry is not changed, except possibly the approximated
## intersections between the zero level-set and grid edges due to slight
## variations in the actual values of @var{phi}.
##
## Exactly zero values are interpreted according to their sign bit if the
## @code{signbit} function is available (on newer versions of GNU Octave).
## If the function is not available, then zeros are assumed to be
## @strong{not} part of the level-set domain.
## 
## @seealso{ls_inside}
## @end deftypefn

function phi = ls_normalise (phi, h = 1, zerotol = 1e-3)
  if (nargin () < 1 || nargin () > 3)
    print_usage ();
  endif

  zerotol *= h;
  exz = (phi == 0);
  if (exist ("signbit") == 5)
    phi(exz) = zerotol * (1 - 2 * double (signbit (phi(exz))));
  else
    phi(exz) = zerotol;
  endif
  zeroPts = (abs (phi) < zerotol);
  phi(zeroPts) = zerotol * sign (phi(zeroPts));

  assert (all (abs (phi(:)) >= zerotol));
endfunction

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Tests.

% Test for error conditions.
%!error <Invalid call to>
%!  ls_normalise ()
%!error <Invalid call to>
%!  ls_normalise (1, 2, 3, 4)

%!test
%!  h = 0.1;
%!  zeroTol = 0.2;
%!  phi = ones (4, 4);
%!  phiEx = phi;
%!  phi(2 : 3, 2 : 3) = [-eps, -0; 0, eps];
%!  phiEx(2 : 3, 2 : 3) = [-zeroTol*h, -zeroTol*h; zeroTol*h, zeroTol*h];
%!  phin = ls_normalise (phi, h, zeroTol);
%!  if (exist ("signbit") == 5)
%!    assert (phin, phiEx);
%!  else
%!    warning ("'signbit' function not available, skipping test.");
%!  endif
