function validPositionsLogMat = formvalidpositionslogicalmatrix( discreteCoordsTrajectory, yDim, xDim, smoothingWidth )
    % Build a matrix whose rows and columns correspond to the
    % discretisation grid to be used, and containing logicals that indicate
    % whether each position is considered 'valid' or 'invalid' (inside the
    % environment or outside).
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % validPositionsLogMat - a 2D matrix with number of rows equal to the
    % Y-dimension size of the discretisation grid and number of columns
    % equal to the X-dimension size of the discretisation grid. It contains
    % logicals only.
    %
    % discreteCoordsTrajectory - an n by 2 matrix of positive integers.
    % These are the processed, discretised observed positions.
    %
    % yDim, xDim - the size of the discretisation grid we use in the Y- and
    % X-dimensions respectively; i.e. the number of grid squares that cover
    % the environment in each dimension.
    %
    % smoothingWidth - positive integer. This defines the maximum number of
    % consecutive invalid discrete positions (in a row or column) we will
    % consider as candidates to convert to valid positions in an effort to
    % 'smooth out' unvisited regions. Thus we make more of the environment
    % accessible than was actually visited, approximating the true spatial
    % extent of the environment. See below for more information. A larger
    % value will fill out more valid regions, but runs a greater risk of
    % making regions valid that should be considered invalid. Some
    % experimentation will be needed to optimise this for the desired
    % resolution.
    %
    % There are three stages. First we use the processed 2D discrete
    % position observations, discreteCoordsTrajectory, to identify
    % positions that are definitely valid. Second we consider other
    % positions to be valid when they lie between two consecutively visited
    % positions. Third, we fill in more invalid regions by smoothing
    % regions between positions that are certainly valid.
    %
    % Note: in the last stage, we look at rows then columns of the discrete
    % grid, and form two logical matrices of candidate valid positions.
    % Only if BOTH dimensions' candidates agree do we assign a new valid
    % position. If we were to use EITHER and not necessarily both, we run
    % the risk of connecting parts of the environment via a bridge of valid
    % positions that should not be considered connected.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % CHANGELOG
    % 29.09.2014 - copied from old version.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    if size(discreteCoordsTrajectory, 2) ~= 2,
        error('discreteCoordsTrajectory must have 2 columns: discrete Y coords and X coords!')
    end
    if nargin < 2,
        dims = max(discreteCoordsTrajectory, [], 1);
        yDim = dims(1);
        xDim = dims(2);
    else
        if rem(yDim, 1) ~= 0,
            error('yDim must be a positive integer!')
        end
        if yDim < 1,
            error('yDim must be a positive integer!')
        end
        if rem(xDim, 1) ~= 0,
            error('xDim must be a positive integer!')
        end
        if xDim < 1,
            error('xDim must be a positive integer!')
        end
    end
    if nargin < 4,
        minXY = min([yDim, xDim]);
        % An arbitrary default.
        smoothingWidth = ceil(minXY / 5);
    else
        if rem(smoothingWidth, 1) ~= 0,
            error('smoothingWidth must be a positive integer!')
        end
        if smoothingWidth < 1,
            error('smoothingWidth must be a positive integer!')
        end
    end
    
    validPositionsLogMat = false([yDim, xDim]);
    
    % First stage: set positions visited as valid.
    validPositionsLogMat(sub2ind([yDim, xDim], discreteCoordsTrajectory(:, 1), discreteCoordsTrajectory(:, 2))) = true;
    
    % Now we 'fill in the gaps'.
    % Firstly: join up consecutively visited positions so that there are no
    % invalid positions between them.
    validPositionsLogMat = linearinterpolationofvalidpositions( validPositionsLogMat, discreteCoordsTrajectory );
    
    % Now we do two sweeps over all positions to fill in the remaining
    % gaps. First we loop over every element of every row, marking
    % currently invalid positions as candidates for being valid if they are
    % in range of two valid positions either side.
    candidateValidYPositionsLogMat = false([yDim, xDim]);
    % Loop over rows.
    for y = 1:yDim,
        % Segment markers are valid positions bordering an invalid position
        % on the left or on the right.
        inds = find(validPositionsLogMat(y, :) & ([true, ~validPositionsLogMat(y, 1:(end - 1))] | [~validPositionsLogMat(y, 2:end), true]));
        if isempty(inds),
            continue;
        end
        nInds = length(inds);
        % First part of row.
        if inds(1) ~= 1,
            if inds(1) <= smoothingWidth + 1,
                candidateValidYPositionsLogMat(y, 1:(inds(1) - 1)) = true;
            end
        end
        % Middle part.
        for iInd = 2:nInds,
            if inds(iInd) - inds(iInd - 1) <= smoothingWidth + 1,
                candidateValidYPositionsLogMat(y, (inds(iInd - 1) + 1):(inds(iInd) - 1)) = true;
            end
        end
        % Last part of row.
        if inds(end) ~= xDim,
            if xDim - inds(end) <= smoothingWidth,
                candidateValidYPositionsLogMat(y, (inds(end) + 1):end) = true;
            end
        end
    end
    
    candidateValidXPositionsLogMat = false([yDim, xDim]);
    % Loop over columns.
    for x = 1:xDim,
        % Segment markers are valid positions bordering an invalid position
        % above or below.
        inds = find(validPositionsLogMat(:, x) & ([true; ~validPositionsLogMat(1:(end - 1), x)] | [~validPositionsLogMat(2:end, x); true]));
        if isempty(inds),
            continue;
        end
        nInds = length(inds);
        % First part of column.
        if inds(1) ~= 1,
            if inds(1) <= smoothingWidth + 1,
                candidateValidXPositionsLogMat(1:(inds(1) - 1), x) = true;
            end
        end
        % Middle part.
        for iInd = 2:nInds,
            if inds(iInd) - inds(iInd - 1) <= smoothingWidth + 1,
                candidateValidXPositionsLogMat((inds(iInd - 1) + 1):(inds(iInd) - 1), x) = true;
            end
        end
        % Last part of column.
        if inds(end) ~= xDim,
            if yDim - inds(end) <= smoothingWidth,
                candidateValidXPositionsLogMat((inds(end) + 1):end, x) = true;
            end
        end
    end
    
    validPositionsLogMat = validPositionsLogMat | (candidateValidYPositionsLogMat & candidateValidXPositionsLogMat);
end