function [theHull, nonUnique] = trihull(theTri)

% trihull -- Indices of boundary of triangulation.
%  trihull(theTri) returns the indices of the bounding
%   polygon associated with theTri triangulation.  This
%   corresponds to the convex-hull if the triangles form
%   a filled convex set.  For triangulations that contain
%   holes, the individual segments are separated by NaNs.
%  [theHull, nonUnique] = trihull(theTri) also returns
%   nonUnique = TRUE (non-zero) if any point appears in
%   more than one segment.
 
% 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 02-Jul-1999 17:02:50.
% Updated    09-Jul-1999 15:31:56.

if nargin < 1
	help(mfilename)
	theTri = 'demo';
end

if isequal(theTri, 'demo'), theTri = 10; end
if ischar(theTri), theTri = eval(theTri); end

if length(theTri) == 1
	nPoints = theTri;
	x = rand(nPoints, 1); y = rand(size(x));
	tri = delaunay(x, y);
	h = feval(mfilename, tri);
	trimesh(tri, x, y, x*0)
	view(2)
	px = x(h); py = y(h);
	px(end+1) = px(1); py(end+1) = py(1);
	hold on
	plot(px, py, '-bo')
	hold off
	f = findobj(gcf, 'Type', 'patch');
	theBDF = [mfilename ' ' int2str(nPoints)];
	title(theBDF)
	set(f, 'buttondownfcn', theBDF)
	set(gcf, 'Name', [mfilename ' Demo'])
	zoomsafe
	figure(gcf)
	if nargout > 0, theHull = h; end
	return
end

t = [theTri(:, [1 2]); theTri(:, [2 3]); theTri(:, [3 1])];

m = max(max(t)); n = m;

s = sparse(t(:, 1), t(:, 2), ones(size(t(:, 1))), m, n);

t = sort(t.').';
s1 = sparse(t(:, 1), t(:, 2), ones(size(t(:, 1))), m, n);

s1 = s1 + s1.';

[i, j] = find(s == 1 & s1 == 1);   % Too slow.

[i, indices] = sort(i);
j = j(indices);

connect(i) = j;

h = zeros(size(i));
f = find(connect);
f = f(1);
h(1) = connect(f);
connect(f) = 0;
starts(1) = 1;

for k = 2:length(h)
%	remaining = length(h)-k+1;
%	if rem(remaining, 1000) == 0 & k > 2
%		disp([' ## Remaining: ' int2str(remaining) ' edges.'])
%	end
	if connect(h(k-1))
		h(k) = connect(h(k-1));
		connect(h(k-1)) = 0;
	else
		f = find(connect);
		if any(f)
			f = f(1);
			h(k) = connect(f);
			connect(f) = 0;
			starts(end+1) = k;
		else
			break
		end
	end
end

if 0 & length(starts) > 1
	disp([' ## Segments: ' int2str(length(starts))])
end

% Check perimeters for points represented more than once.

htemp = h(h ~= 0);
s = sparse(htemp, htemp, ones(size(htemp)));
[i, j] = find(s > 1);
nonUnique = any(i);
if nonUnique & nargout < 2
	disp([' ## ' mfilename ': Some perimeters overlap.'])
end

if length(starts) > 1
	htemp = [];
	starts(end+1) = length(h) + 1;
	for k = 1:length(starts)-1
		i = starts(k):starts(k+1)-1;
		if k > 1, htemp = [htemp; NaN]; end
		htemp = [htemp; h(i)];
	end
	h = htemp;
end

if nargout > 0
	theHull = h;
else
	assignin('caller', 'ans', h)
end
