function m = leaf_locate_vertex( m, varargin )
%m = leaf_locate_vertex( m, ... )
%   Ensure that certain degrees of freedom of a single node remain
%   constant.  This is ensured by translating the mesh so as to restore the
%   values of the specified coordinates, after each iteration.
%
%   Options:
%       'vertex'    The vertex to be held stationary.  If the empty list is
%                   supplied, no vertex will be fixed and dfs is ignored.
%       'dfs'       The degrees of freedom to be held stationary.  This is a
%                   string made of the letters 'x', 'y', and 'z'.  This
%                   defaults to 'xyz', i.e. fix the vertex completely.
%   Each degree of freedom not in dfs will be unconstrained.
%
%   It is only possible to fix a vertex in directions parallel to the
%   axes.
%
%   Equivalent GUI operation: clicking on the mesh while the Mesh editor
%   panel is selected and 'Locate' is selected in the Fix/Delete 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
    if ~isempty( s.vertex )
        vx = s.vertex(1);
        if (vx < 1) || (vx > size(m.nodes,1))
            complain( mfilename(), 'Invalid vertex %d. Command ignored.' );
            return;
        end
    end
    if numel(s.vertex) > 1
        fprintf( 1, '%s: %d nodes supplied, only the first, %d, used.\n', ...
            mfilename(), numel(s.vertex), vx );
    end
    
    dfbits = convertXYZtoDFs( s.dfs );
    if isempty( s.vertex )
        m.globalDynamicProps.locatenode = 0;
        m.globalDynamicProps.locateDFs = [0 0 0];
    else
        m.globalDynamicProps.locatenode = vx;
        m.globalDynamicProps.locateDFs = dfbits;
    end
end
