function m = leaf_fix_vertex( m, varargin )
%m = leaf_fix_vertex( m, ... )
%   Constrain vertexes of the mesh so that they are only free to move along
%   certain axes; or remove such constraints.
%
%   Options:
%       'vertex'    The vertexes to be constrained or unconstrained.  If
%                   the empty list is supplied, the set of all vertexes is
%                   used.
%       'dfs'       The degrees of freedom to be constrained.  This is a
%                   string made of the letters 'x', 'y', and 'z'.  This
%                   defaults to 'xyz', i.e. fix the vertexes completely.
%                   Each degree of freedom not in dfs will be made
%                   unconstrained for all of the given vertexes.  Vertexes
%                   not in the list of vertexes will have their constraints
%                   left unchanged.
%
%   Note that to remove all constraints from all vertexes, do this:
%
%       m = leaf_fix_vertex( m, 'vertex', [], 'dfs', '' );
%
%   It is only possible to constrain vertexes in directions parallel to the
%   axes.
%
%   Invalid vertex indexes will be detected, warned about, and ignored.  If
%   you receive such a warning you should check the indexes you are
%   supplying, since the fact of some of them being out of range may cast
%   doubt on the correctness of the others.
%
%   Equivalent GUI operation: clicking on the mesh while the Mesh editor
%   panel is selected and 'Fix' is selected in the mouse-mode menu.  The
%   'x', 'y', and 'z' checkboxes specify which degrees of freedom to
%   constrain or unconstrain.
%
%   Topics: Mesh editing.

    if isempty(m), return; end
    [s,ok] = safemakestruct( mfilename(), varargin );
    if ~ok, return; end
    s = defaultfields( s, 'dfs', 'xyz' );
    ok = checkcommandargs( mfilename(), s, 'exact', ...
        'vertex', 'dfs' );
    if ~ok, return; end
    
    dfbits = convertXYZtoDFs( s.dfs );
    dfbits = [ dfbits, dfbits ];
    if any( s.vertex < 1 )
        beep;
        fprintf( 1, '** %s: invalid vertex indexes < 1 found:', mfilename() );
        fprintf( 1, ' %d', s.vertex(s.vertex < 1) );
        fprintf( 1, '\n    Invalid values ignored.\n' );
        s.vertex = s.vertex(s.vertex >= 1);
    end
    if any( s.vertex > size(m.nodes,1) )
        beep;
        fprintf( 1, '** %s: some vertex indexes exceed the number of nodes (%d):', ...
            mfilename(), size(m.nodes,1) );
        fprintf( 1, ' %d', s.vertex( s.vertex > size(m.nodes,1) ) );
        fprintf( 1, '\n    Invalid values ignored.\n' );
        s.vertex = s.vertex( s.vertex <= size(m.nodes,1) );
    end
    if isempty( s.vertex )
        for i=1:size(m.nodes,1)
            m.fixedDFmap( i, : ) = dfbits;
        end
    else
        for i=1:length(s.vertex)
            m.fixedDFmap( s.vertex(i), : ) = dfbits;
        end
    end
end
