function [mask weight] = mesh2vol(node, elem, xi, yi, zi)
%
% [mask weight]=mesh2vol(node,face,Nxyz)
% [mask weight]=mesh2vol(node,face,[Nx,Ny,Nz])
% [mask weight]=mesh2vol(node,face,xi,yi,zi,hf)
%   or
% newval=mesh2vol(node_val,face,...)
%
% fast rasterization of a 3D mesh to a volume with tetrahedron index labels
%
% author: Qianqian Fang <q.fang at neu.edu>
% date for initial version: Feb 10,2014
%
% input:
%      node: node coordinates, dimension N by 2 or N by 3 array
%      nodeval: a 4-column array, the first 3 columns are the node coordinates,
%            the last column denotes the values associated with each node
%      face: a triangle surface, N by 3 or N by 4 array
%      Nx,Ny,Nxy: output image in x/y dimensions, or both
%      xi,yi: linear vectors for the output pixel center positions in x/y
%      hf: the handle of a pre-created figure window for faster rendering
%
% output:
%      mask: a 3D image, the value of each pixel is the index of the
%            enclosing triangle, if the pixel is outside of the mesh, NaN
%      weight: (optional) a 3 by Nx by Ny array, where Nx/Ny are the dimensions
%            for the mask
%      newval: when the node has 4 columns, the last column represents the
%            values (color) at each node, the output newval is the rasterized
%            mesh value map over the specified grid.
%
% note: This function only works for matlab
%
% example:
%
%   [no,el]=meshgrid6(0:5,0:5,0:3);
%   mask=mesh2vol(no,el(:,1:4),0:0.1:5,0:0.1:5,0:0.1:4);
%   imagesc(mask(:,:,3))
%
% -- this function is part of iso2mesh toolbox (http://iso2mesh.sf.net)
%

nodeval = [];
if (size(node, 2) == 4)
    nodeval = node(:, 4);
    node(:, 4) = [];
end

if (nargin == 3 && length(xi) == 1 && xi > 0)
    mn = min(node);
    mx = max(node);
    df = (mx(1:min(3, size(node, 2))) - mn(1:min(3, size(node, 2)))) / xi;
elseif (nargin == 3 && length(xi) == 3 && all(xi > 0))
    mn = min(node);
    mx = max(node);
    df = (mx(1:min(3, size(node, 2))) - mn(1:min(3, size(node, 2)))) ./ (xi(:)');
elseif (nargin == 5)
    mx = [max(xi) max(yi) max(zi)];
    mn = [min(xi) min(yi) min(zi)];
    df = [min(diff(xi(:))) min(diff(yi(:))) min(diff(zi(:)))];
else
    error('you must give at least xi input');
end

xi = mn(1):df(1):mx(1);
yi = mn(2):df(2):mx(2);
zi = mn(3):df(3):mx(3);

if (size(node, 2) ~= 3 || size(elem, 2) <= 3)
    error('node must have 3 columns; face can not have less than 3 columns');
end

nz = length(zi);
mask = zeros(length(xi) - 1, length(yi) - 1, length(zi) - 1);
if (nargout > 1 || ~isempty(nodeval))
    weight = zeros(4, length(xi) - 1, length(yi) - 1, length(zi) - 1);
end

hf = figure('visible', 'on');
for i = 1:nz
    if (~isempty(nodeval))
        [cutpos, cutvalue, facedata, elemid] = qmeshcut(elem, node, nodeval, ['z=' num2str(zi(i))]);
    else
        [cutpos, cutvalue, facedata, elemid] = qmeshcut(elem, node, node(:, 1), ['z=' num2str(zi(i))]);
    end
    if (isempty(cutpos))
        continue
    end
    if (nargout > 1 || ~isempty(nodeval))
        [maskz, weightz] = mesh2mask(cutpos, facedata, xi, yi, hf);
        weight(:, :, :, i) = weightz;
    else
        maskz = mesh2mask(cutpos, facedata, xi, yi, hf);
    end
    idx = find(~isnan(maskz));
    if (~isempty(nodeval))
        eid = facedata(maskz(idx), :);
        maskz(idx) = cutvalue(eid(:, 1)) .* weightz(1, idx)' + cutvalue(eid(:, 2)) .* weightz(2, idx)' + ...
            cutvalue(eid(:, 3)) .* weightz(3, idx)' + cutvalue(eid(:, 4)) .* weightz(4, idx)';
    else
        maskz(idx) = elemid(maskz(idx));
    end
    mask(:, :, i) = maskz;
end
close(hf);
