function hm = plotmesh(node, varargin)
%
% hm=plotmesh(node,face,elem,opt)
%
% plot surface and volumetric meshes
%
% author: Qianqian Fang <q.fang at neu.edu>
%
% input:
%      node: a node coordinate list, 3 columns for x/y/z; if node has a
%            4th column, it will be used to set the color at each node.
%      face: a triangular surface face list; if face has a 4th column,
%            it will be used to separate the surface into
%            sub-surfaces and display them in different colors;
%            face can be a cell array, each element of the array represents
%            a polyhedral facet of the mesh, if an element is an array with
%            two array subelements, the first one is the node index, the
%            second one is a scalar as the group id of the facet.
%      elem: a tetrahedral element list; if elem has a 5th column,
%            it will be used to separate the mesh into
%            sub-domains and display them in different colors.
%      opt:  additional options for the plotting
%
%            for simple point plotting, opt can be markers
%            or color options, such as 'r.', or opt can be
%            a logic statement to select a subset of the mesh,
%            such as 'x>0 & y+z<1', or an equation defining
%            a plane at which a mesh cross-section is plotted, for
%            example 'y=2*x'; opt can have more than one
%            items to combine these options, for example:
%            plotmesh(...,'x>0','r.'); the range selector must
%            appear before the color/marker specifier
%
% in the event where all of the above inputs have extra settings related to
% the color of the plot, the priorities are given in the following order:
%
%          opt > node(:,4) > elem(:,5) > face(:,4)
%
% output:
%   hm: handle or handles (vector) to the plotted surfaces
%
% example:
%
%   h=plotmesh(node,'r.');
%   h=plotmesh(node,'x<20','r.');
%   h=plotmesh(node,face);
%   h=plotmesh(node,face,'y>10');
%   h=plotmesh(node,face,'facecolor','r');
%   h=plotmesh(node,elem,'x<20');
%   h=plotmesh(node,elem,'x<20 & y>0');
%   h=plotmesh(node,face,elem);
%   h=plotmesh(node,face,elem,'linestyle','--');
%   h=plotmesh(node,elem,'z=20');
%
% -- this function is part of iso2mesh toolbox (http://iso2mesh.sf.net)
%

selector = [];
opt = [];
face = [];
elem = [];

if (nargin > 1)
    hasopt = 0;
    for i = 1:length(varargin)
        if (ischar(varargin{i}))
            if (~isempty(regexp(varargin{i}, '[x-zX-Z]')) && ~isempty(regexp(varargin{i}, '[><=&|]')))
                selector = varargin{i};
                if (nargin >= i + 1)
                    opt = varargin(i + 1:end);
                end
            else
                opt = varargin(i:end);
            end
            if (i == 1)
                face = [];
                elem = [];
            elseif (i == 2)
                if (iscell(varargin{1}) || size(varargin{1}, 2) < 4)
                    face = varargin{1};
                    elem = [];
                elseif (size(varargin{1}, 2) == 4)
                    faceid = unique(varargin{1}(:, 4));
                    if (length(faceid) == 1)
                        face = varargin{1};
                        elem = [];
                    elseif (any(hist(varargin{1}(:, 4), unique(varargin{1}(:, 4))) > 50))
                        face = varargin{1};
                        elem = [];
                    else
                        elem = varargin{1};
                        face = [];
                    end
                else
                    elem = varargin{1};
                    face = [];
                end
            elseif (i == 3)
                face = varargin{1};
                elem = varargin{2};
            end
            hasopt = 1;
            break
        end
    end
    if (hasopt == 0)
        if (length(varargin) >= 2)
            face = varargin{1};
            elem = varargin{2};
            if (length(varargin) > 2)
                opt = varargin(3:end);
            end
        elseif (iscell(varargin{1}) || size(varargin{1}, 2) < 4)
            face = varargin{1};
            elem = [];
        elseif (size(varargin{1}, 2) == 4)
            faceid = unique(varargin{1}(:, 4));
            if (length(faceid) == 1)
                face = varargin{1};
                elem = [];
            elseif (any(hist(varargin{1}(:, 4), unique(varargin{1}(:, 4))) > 50))
                face = varargin{1};
                elem = [];
            else
                elem = varargin{1};
                face = [];
            end
        else
            elem = varargin{1};
            face = [];
        end
    end
end

holdstate = ishold;
if (~holdstate)
    cla;
end
if (size(node, 2) == 4 && size(elem, 2) == 5)
    warning(['You have specified the node colors by both the 4th ' ...
             'and 5th columns of node and face inputs, respectively. ' ...
             'The node input takes priority']);
end
if (isempty(face) && isempty(elem))
    if (isempty(selector))
        if (isempty(opt))
            h = plot3(node(:, 1), node(:, 2), node(:, 3), 'o');
        else
            h = plot3(node(:, 1), node(:, 2), node(:, 3), opt{:});
        end
    else
        x = node(:, 1);
        y = node(:, 2);
        z = node(:, 3);
        idx = eval(['find(' selector ')']);
        if (~isempty(idx))
            if (isempty(opt))
                h = plot3(node(idx, 1), node(idx, 2), node(idx, 3), 'o');
            else
                h = plot3(node(idx, 1), node(idx, 2), node(idx, 3), opt{:});
            end
        else
            warning('nothing to plot');
        end
    end
end

if (~isempty(face))
    hold on;
    if (isempty(selector))
        if (isempty(opt))
            h = plotsurf(node, face);
        else
            h = plotsurf(node, face, opt{:});
        end
    else
        if (iscell(face))
            cent = meshcentroid(node, face);
        else
            cent = meshcentroid(node, face(:, 1:3));
        end
        x = cent(:, 1);
        y = cent(:, 2);
        z = cent(:, 3);
        idx = eval(['find(' selector ')']);
        if (~isempty(idx))
            if (iscell(face))
                h = plotsurf(node, face(idx), opt{:});
            else
                h = plotsurf(node, face(idx, :), opt{:});
            end
        else
            warning('no surface to plot');
        end
    end
end

if (~isempty(elem))
    hold on;
    if (isempty(selector))
        if (isempty(opt))
            h = plottetra(node, elem);
        else
            h = plottetra(node, elem, opt{:});
        end
    else
        cent = meshcentroid(node, elem(:, 1:4));
        x = cent(:, 1);
        y = cent(:, 2);
        z = cent(:, 3);
        if (regexp(selector, '='))
            if (size(node, 2) == 4)
                [cutpos, cutvalue, facedata] = qmeshcut(elem, node(:, 1:3), node(:, 4), selector);
            elseif (size(node, 2) == 3)
                [cutpos, cutvalue, facedata] = qmeshcut(elem, node, node(:, 3), selector);
            else
                error('plotmesh can only plot 3D tetrahedral meshes');
            end
            if (~isreal(cutvalue))
                cutvalue = abs(cutvalue);
            end
            h = patch('Vertices', cutpos, 'Faces', facedata, 'FaceVertexCData', cutvalue, 'facecolor', 'interp', opt{:});
        else
            idx = eval(['find(' selector ')']);
            if (~isempty(idx))
                if (isempty(opt))
                    h = plottetra(node, elem(idx, :));
                else
                    h = plottetra(node, elem(idx, :), opt{:});
                end
            else
                warning('no tetrahedral element to plot');
            end
        end
    end
end

if (exist('h', 'var') && ~holdstate)
    hold off;
end
if (exist('h', 'var'))
    if (any(get(gca, 'dataaspectratio') > 1e8))
        view(3);
    end
    axis equal;
end
if (exist('h', 'var') && nargout >= 1)
    hm = h;
end
