function [tout, xo, yo, io] = triclean(tri, x, y, ind, verbose)

% triclean -- Triangle clean-up.
%  triclean(tri, x, y, ind) cleans-up the output of "tripoly"
%   by combining triangles and flipping quadralaterals that
%   involve "fake" points, until the interior triangles no
%   longer have any such points.  The triangle vertices that
%   are indexed in "tri" correspond to the polygon perimeter
%   (x, y); the original polygon points (as output by "tripoly")
%   are indexed in "ind".  The same information is returned,
%   now cleaned-up.  Only the counter-clockwise triangles remain.
 
% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO.
%  All Rights Reserved.
%   Disclosure without explicit written consent from the
%    copyright owner does not constitute publication.
 
% Version of 26-Jul-1999 15:24:23.
% Updated    29-Jul-1999 14:07:29.

if nargin < 1, help(mfilename), return, end
if nargin < 5, isVerbose = 0; end

result = [];

s = trisense(tri, x, y);
ccw = find(s > 0);
cw = find(s < 0);

if any(cw), tri(cw, :) = []; end

to = tri; xo = x; yo = y; io = ind;

tic

done = 0;
while ~done
	done = 1;

% In the first pass, we squeeze adjacent triangles
%  together, if they have a simple geometry.  The
%  slowest lines are "f = find(to...)" and the next.
%  Also the calls to "trisort" and "uniq".

to = [to(:, [1 2 3]); to(:, [1 3 2]); to(:, [2 1 3]); ...
		to(:, [2 3 1]); to(:, [3 1 2]); to(:, [3 2 1])];

	squeezed = 1;
	while any(squeezed)
		squeezed = 0;
		fake = ones(size(xo));
		fake(io) = 0;
		fake = find(fake);
		if isempty(fake), break, end
		if rem(length(fake), 10) == 0
			disp([' ## Remaining: ' int2str(length(fake))])
		end
		for k = 1:length(fake)
			node = fake(k);
			before = rem(node - 2 + length(xo), length(xo)) + 1;
			after = rem(node, length(xo)) + 1;
			f = find(to(:, 1) == before & to(:, 2) == node);   % Slow 23-31%.
			g = find(to(:, 1) == node & to(:, 2) == after);   % Slow 22-30%.
			for j = 1:length(g)
				for i = 1:length(f)
					if to(f(i), 3) == to(g(j), 3)
						opposite = to(f(i), 3);
						temp = sort([before opposite after]);
						indices = [1 2 3; 1 3 2; 2 1 3; ...
									2 3 1; 3 1 2; 3 2 1];
						tnew = temp(indices);
						if isVerbose
							disp([' ## Squeezed: ' int2str(node) ...
								' ' mat2str(to(f(i), :)) ...
								' ' mat2str(to(g(j), :)) ...
								' ' mat2str(tnew(1, :))])
						end
						h = find(any(to.' == node));
						to(h(1:6), :) = tnew;
						to(h(7:end), :) = [];
						xo(node) = [];
						yo(node) = [];
						io(io == node) = [];
						io(io > node) = io(io > node) - 1;
						to(to > node) = to(to > node) - 1;
						squeezed = 1;
						done = 0;
						break
					end
				end
				if squeezed, break, end
			end
			if squeezed, break, end
		end
	end
	
	to = trisort(to);   % Slow 7-13%.
	to = uniq(to);   % Slow 7-12%.
	
	s = trisense(to, xo, yo);
	cw = (s < 0);
	if any(cw), to(cw, :) = fliplr(to(cw, :)); end

% In the second pass, we flip one convex quadralateral
%  that involves a fake point.  Then, we go back to
%  pass #1.

	[m, n] = size(to);
	to = [to(:, [1 2 3]); to(:, [1 3 2]); to(:, [2 1 3]); ...
			to(:, [2 3 1]); to(:, [3 1 2]); to(:, [3 2 1])];
					
	indices = (1:m).';
	indices = indices * ones(1, 6);
	to = [to indices(:)];
	
	flipped = 1;
	
	while any(flipped)
		flipped = 0;
		flag = 0;
		fake = ones(size(xo));
		fake(io) = 0;
		fake = find(fake);
		if isempty(fake), break, end
		for k = 1:length(fake)
			node = fake(k);
			f = find(to(:, 1) == node);
			for j = 1:length(f)-1
				for i = j+1:length(f)
					if to(f(i), 2) == to(f(j), 2)
						a = node;
						b = to(f(i), 3);
						c = to(f(i), 2);
						d = to(f(j), 3);
						abcd = [a b c d];
						xtemp = xo(abcd);
						ytemp = yo(abcd);
						if isconvex(xtemp, ytemp)
							if isVerbose
								disp([' ## Flipped: ' mat2str([a b c d])])
							end
							triangle = to(f(i), 4);
							h = find(to(:, 4) == triangle);
							to(h(1), :) = [a b d triangle];
							triangle = to(f(j), 4);
							h = find(to(:, 4) == triangle);
							to(h(1), :) = [b c d triangle];
							flipped = 1;
							done = 0;
							break
						end
					end
				end
				if flipped, break, end
			end
			if flipped, break, end
		end
		flipped = 0;   % Do just one.
	end
	
	to = to(1:m, 1:3);
	to = trisort(to);
	to = uniq(to);
	
	s = trisense(to, xo, yo);
	cw = (s < 0);
	if any(cw), to(cw, :) = fliplr(to(cw, :)); end
end

toc

if nargout > 0
	tout = to;
else
	assignin('caller', 'ans', to)
end

fake = ones(length(x), 1);
fake(ind) = 0;
fake = find(fake);

subplot(1, 2, 1)
delete(get(gca, 'Children'))
hold off
axis normal
tripatch(tri, x, y)
hold on
% plot(x(ind), y(ind), 'o-')
plot(x(fake), y(fake), '+')
hold off
zoomsafe out

fake = ones(length(xo), 1);
fake(io) = 0;
fake = find(fake);

subplot(1, 2, 2)
delete(get(gca, 'Children'))
hold off
axis normal
tripatch(to, xo, yo)
hold on
% plot(xo(io), yo(io), 'o-')
plot(xo(fake), yo(fake), '+')
hold off
zoomsafe out

zoomsafe all
