function theResult = grid2mask(x, y, z, c, mask)

% grid2mask -- Create an interactive mask.
%  grid2mask('demo') demonstrates itself via "grid2mask(10)".
%  grid2mask(N) demonstrates itself with an N-by-N grid.
%  grid2mask(x, y, z, c, mask) creates a masked surface from the
%   (x, y, z, c, mask) grid, whose cells can be toggled with mouse
%   clicks.  A mouse click on a grid cell causes the corresponding
%   color to toggle to/from transparency.  The default z is 0;
%   the default c is taken from "surf(x, y, z)".  The mask is
%   a logical array that defaults to all FALSE.
%   A handle is returned, whose "UserData" contains the handles
%   of surfaces that can be used to reassemble the c array.
%  grid2mask(h, 'set', mask) sets the current state of the mask.
%  grid2mask(h, 'get') returns the current state of the mask.
%  grid2mask(h, 'done') returns the current state of the mask
%   and deletes the mask objects.

% 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 07-Oct-1999 15:33:50.
% Updated    28-Jun-2000 17:53:52.

if nargin < 1, help(mfilename), return, end

% Demonstration.

if nargin == 1 & ~isequal(lower(x), 'buttondownfcn')
	f = findobj(gcf, 'Tag', mfilename);
	delete(f)
	nx = x;
	if ischar(nx), nx = eval(nx); end
	ny = nx;
	[x, y] = meshgrid(0:nx, 0:ny);
	z = rand(size(x));
	h = feval(mfilename, x, y, z);
	set(gcf, 'Name', mfilename)
	zoomsafe
	if nargout > 0
		theResult = h;
	else
		assignin('caller', 'ans', h)
	end
	return
end

if nargin > 2 & isequal(lower(y), 'set')
	h = x;
	if nargin < 3 | isempty(z), z = 0; end
	mask = ~~z
	if length(mask) == 1
		mask = ~~(zeros(size(x)) + mask);
	end
	u = get(h, 'UserData');
	x = get(u(1), 'XData');
	c = zeros(length(u)+1, length(x));
	for i = 1:length(u)
		c(i:i+1, :) = get(u(i), 'UserData');
	end
	if all(mask(:))
		c(:) = NaN;
	else
		c(mask) = NaN;   % Only does c(1, 1) if all ones.
	end
	for i = 1:length(u)
		set(u(i), 'CData', c(i:i+1, :));
	end
	if nargout > 0
		theResult = isnan(c);
	else
		assignin('caller', 'ans', isnan(c))
	end
	return
end

if nargin > 1 & isequal(lower(y), 'get')
	h = x;
	u = get(h, 'UserData');
	x = get(u(1), 'XData');
	c = zeros(length(u)+1, length(x));
	for i = 1:length(u)
		c(i:i+1, :) = get(u(i), 'CData');
	end
	if nargout > 0
		theResult = isnan(c);
	else
		assignin('caller', 'ans', isnan(c))
	end
	return
end

if nargin > 1 & isequal(lower(y), 'done')
	h = x;
	u = get(h, 'UserData');
	x = get(u(1), 'XData');
	c = zeros(length(u)+1, length(x));
	for i = 1:length(u)
		c(i:i+1, :) = get(u(i), 'CData');
	end
	delete(u)
	delete(h)
	if nargout > 0
		theResult = isnan(c);
	else
		assignin('caller', 'ans', isnan(c))
	end
	return
end

% Handle mouse click.

if nargin == 1 & isequal(lower(x), 'buttondownfcn')
	h = gco;
	x = get(h, 'XData');
	y = get(h, 'YData');
	z = get(h, 'ZData');
	c = get(h, 'CData');
	cx = sum(x); cx = 0.25 * (cx(1:end-1) + cx(2:end));
	cy = sum(y); cy = 0.25 * (cy(1:end-1) + cy(2:end));
	cz = cx + cy*sqrt(-1);
	pt = get(gca, 'CurrentPoint');
	pt = pt(1, 1:2); ptx = pt(1); pty = pt(2);
	ptz = ptx + pty*sqrt(-1);
	dz = abs(cz - ptz);
	f = find(dz == min(dz));
	if any(f)
		f = f(1);
		if isnan(c(1, f))
			c_original = get(h, 'UserData');
			c(1, f) = c_original(1, f);
		else
			c(1, f) = NaN;
		end
		set(h, 'CData', c)
	end
	return
end

% Setup.

if nargin < 3, z = []; end
if nargin < 4, c = []; end
if nargin < 5, mask = []; end

if isempty(z), z = zeros(size(x)); end

if isempty(c)
	temp = surface(x, y, z, 'Visible', 'off');
	c = get(temp, 'CData');
	delete(temp)
end

if isempty(mask), mask = ~~zeros(size(x)); end

% CAREFUL: When z contains NaN, the corresponding
%  cell is not clickable, unlike when c contains NaN.
%  We should set the corresponding z to zero and
%  adjust c accordingly.

masked_color = c;
masked_color(logical(mask)) = NaN;

theEraseMode = 'normal';
theEraseMode = 'xor';

for i = 1:size(x, 1)-1
	u(i) = surface(x(i:i+1, :), y(i:i+1, :), ...
			z(i:i+1, :), masked_color(i:i+1, :), ...
			'UserData', c(i:i+1, :), ...
			'EraseMode', theEraseMode);
end

t = text(x(1), y(1), mfilename, 'Visible', 'off', 'Tag', mfilename);

theBDF = [mfilename ' ButtonDownFcn'];
set(u, 'ButtonDownFcn', theBDF, 'Tag', mfilename)
set(t, 'UserData', u)

if nargout > 0
	theResult = t;
else
	assignin('caller', 'ans', t)
end
