## Copyright (C) 2023 Andreas Stahel
##
## 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 2 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, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
## 02110-1301  USA

## -*- texinfo -*-
## @deftypefn {Function File} {} @var{h} = tricontour (@var{tri}, @var{x}, @var{y}, @var{z}, @var{levels}, @var{linestyle})
## Plot level curves for the values of @code{@var{z}} on a triangular mesh in 2D.
##
## parameters:
##@itemize
##@item@var{tri} is the triangular meshing of the points
##@item @var{x}, @var{y} are the coordinates of the points, e.g. as generated by @code{delaunay}.
##@item @var{levels} is a vector with the values of the countour levels.
##@*If @var{levels} is a scalar, then it corresponds to the number of
## level curves to be drawn. If exactly one level curve is desired, list
## the level twice in the vector @var{levels}.
##@item @var{linestyle} is an optional argument to modify the line style.
##@end itemize
##
## output:
##@* @var{h} is the graphic handle to the plot.
## @seealso{trimesh, trisurf, delaunay}
## @end deftypefn

function h = tricontour (tri, x, y, z, levels, varargin)
%%  if (nargin ~= 5)
  if (nargin < 5)
    print_usage ();
  endif

  if isscalar(levels);
    dom = [min(z),max(z)];
    dom = mean(dom)+0.999*(dom-mean(dom));
    levels = linspace(dom(1),dom(2),levels);
  endif
  
  levels = sort(levels);
  pData = [];  cData = [];  pPoints = 0;               
  
  for el = 1:size(tri,1)
    values = z([tri(el,:)]);
    minval = min(values);
    maxval = max(values);
    locallevel = levels((minval<=levels+eps)&(levels<maxval+eps));

    for level = locallevel
      points  = zeros(1,2); npoints = 1;
      dl = values - level;
      
      ind = find(abs(dl)<=10*eps);
      if length(ind)
	points = [x(tri(el,ind)),y(tri(el,ind))];
	npoints += length(ind);
      endif  %% length(ind)
          
      if (npoints<=2)
	if ((dl(1)*dl(2)) < 0)    # intersection between 1st and 2nd point
	  points(npoints,:) = ( dl(2)*[x(tri(el,1)),y(tri(el,1))]...
				-dl(1)*[x(tri(el,2)),y(tri(el,2))])/(dl(2)-dl(1));
	  npoints++;
	endif
	if ((dl(1)*dl(3)) < 0)    # intersection between 1st and 3rd point
	  points(npoints,:) = ( dl(3)*[x(tri(el,1)),y(tri(el,1))]...
				-dl(1)*[x(tri(el,3)),y(tri(el,3))])/(dl(3)-dl(1));
	  npoints++;
	endif
	if ((dl(3)*dl(2)) < 0)    # intersection between 2nd and 3rd point
	  points(npoints,:) = ( dl(2)*[x(tri(el,3)),y(tri(el,3))]...
				-dl(3)*[x(tri(el,2)),y(tri(el,2))])/(dl(2)-dl(3));
	  npoints++;
	endif
      endif  %% npoints<=2
      if npoints==3
	pData = [pData;points; NaN,NaN ];
	pPoints += npoints;
	cData = [cData;level*[1;1;1]];
      endif    
    endfor # level
  endfor # el = 1:size(tri,1)

  if nargin == 5
    h = patch('XData',pData(:,1),'YData',pData(:,2),'CData',cData,'EdgeColor','flat');
  else
    h = patch('XData',pData(:,1),'YData',pData(:,2),'CData',cData,'EdgeColor','flat',varargin{:});
  endif
  
  
%!demo
%! rand ('state', 2)
%! x = rand (100, 1)-0.5;
%! y = rand (100, 1)-0.5;
%! z = (x.^2 + 2*y.^2);
%! tri = delaunay (x, y);
%! tricontour (tri, x, y, z, [0:0.05:1]);
%! axis equal
%! grid on
%!demo
%! rand ('state', 2)
%! x = rand (500, 1)-0.5;
%! y = rand (500, 1)-0.5;
%! z = (x.^2 + 2*y.^2);
%! tri = delaunay (x, y);
%! tricontour (tri, x, y, z, [0.2,0.2],'linewidth',2.5,'edgecolor','red');
%! axis equal
%! grid on
  
