
%% Combine Line Points
%
% Given a specified camera model and accompanying filters on image subject, 
% the line-point .mat files are combined into a single array of points and
% a single lineSizeMat matrix. 
%

%% Input Arguments

% dirPath - Line-point directory path - relative cwd.
%           type: String

% camModel - Name (tag) of camera-model.
%            type: String

% subjFilt - Filter specifier for subject matter of image, from which line
%           points are extracted. Allows for "exclusion" filter. 
%           ex. 'hi ^bye ^hello' = {'hi','bye','hello'}; where ^ is used to
%           indicate exlcuded files.
%           type: String

% fileNames - Optional input file names directly.
%             type: Nx1 cell 


%% Output Arguments

% pts - Normalized coordinate matrix containing ordered list of all line points
%       grouped hiearchically by line and then group (image)
%       type: Nx2 matrix.

% lineSizeMat - Size of sets matrix. Columns correspond to line index,
%               and rows correspond to group (image) index. To deduce number of points 
%               within line segment with group and line index i and j, 
%               respectively then N = setSize(i,j)
%               type: GxL matrix. 

% groupScale - Unified scaling factor (normalization) for line points.
%              type: 2x1 vector

% groupOffset - Unified offset (normalization) for line points.
%               type: 2x1 vector


%% Combine Line Points

function [pts, lineSizeMat, groupScale, groupOffset] = combine_line_points( dirPath, camModel, subjFilt, varargin)

%parse input parameters
[imgSeqFileNames, ~, nImgs] = input_parser(dirPath, camModel, subjFilt, varargin{:});

combinedPts = cell(nImgs, 1);
combinedLineSizeMat = cell(nImgs, 1);
nMaxLines = 0;
nLines  = nan(nImgs, 1);
nGroups = nan(nImgs, 1);

groupScale  = NaN;
groupOffset = NaN;

for i = 1:nImgs,

    filePath = imgSeqFileNames{i};
    
    load(fullfile(dirPath, filePath{1}), 'pts', 'lineSizeMat', 'scale', 'offset');
    
    if isnan(groupScale)
        groupScale = scale;
        groupOffset = offset;
    end
    
    if ~isequal(groupScale, scale) || ~isequal(groupOffset, offset)
        warning('CombineLinePts:UnifyNorm', 'Unifying offset (%f,%f) and scale (%f, %f)', groupOffset, groupScale);
        nPts = size(pts, 1);
        pts(:,1) = ( pts(:,1) + offset(1)*ones(nPts, 1) )*(scale(1)/groupScale(1)) - groupOffset(1)*ones(nPts, 1);
        pts(:,2) = ( pts(:,2) + offset(2)*ones(nPts, 1) )*(scale(2)/groupScale(2)) - groupOffset(2)*ones(nPts, 1);        
    end
            
    combinedPts{i} = pts;
    combinedLineSizeMat{i} = lineSizeMat;
    
    [nGroups(i), nLines(i)] = size(lineSizeMat);        
    if nLines(i) > nMaxLines
        nMaxLines =  nLines(i);
    end
    
end

pts = cell2mat(combinedPts);

lineSizeMat = zeros(sum(nGroups), nMaxLines);
idx = 1;
for i = 1:nImgs,
    lineSizeMat(idx:idx+nGroups(i)-1, 1:nLines(i)) = combinedLineSizeMat{i};
    idx = idx + nGroups(i);
end

end


%% Input Parser

function [imgSeqFileNames, dirPath, nImgs] = input_parser(dirPath, camModel, subjFilt, varargin)

matlabDir = userpath;
matlabDir = matlabDir(1:end-1);

% parse input arguments
p = inputParser;	
p.addRequired('dirPath', @(x) ischar(x));  
p.addRequired('camModel', @(x) ischar(x));
p.addRequired('subject', @(x) ischar(x));
p.addParameter('fileNames', {}, @(x) isa(x, 'cell'));

p.parse(dirPath, camModel, subjFilt, varargin{:});
inputs           = p.Results;
dirPath          = inputs.dirPath;
camModel         = inputs.camModel;
subjFilt         = inputs.subject;
fileNames        = inputs.fileNames;

if isempty(dirPath)
    fullDirPath = '.';
else
    if regexp(dirPath, matlabDir)
        fullDirPath = dirPath;
    elseif strncmp(dirPath, '.', 1)    
        fullDirPath = dirPath;
    else        
        fullDirPath = fullfile(matlabDir, dirPath);
    end
end

%parse sequence name for excluded files
% ex. 'hi ^bye ^hello' = {'hi','bye','hello'}; where ^ is used to indicate
% exlcuded files
subjComps = strsplit(subjFilt, '\s*\^', 'DelimiterType', 'RegularExpression');
shift = 0;
if strcmp(subjComps{1}, 'manip')
    subjTag = subjComps{2}; 
    shift = 1;
else
    subjTag = subjComps{1};     
end

if length(subjComps) > 1+shift
    subjExcl = subjComps{2+shift};
else
    subjExcl = '.';
end

%check image sequence name exists
dirFiles = dir(fullDirPath);
nTotalFiles = length(dirFiles);
imgSeqFileNames = cell(nTotalFiles, 1);
imgIdx = 0;

for name = {dirFiles.name}
   
    nameComps = strsplit(name{1}, '_', 'DelimiterType', 'RegularExpression');
    
    %check for direct matches
    if any(strcmp(name, fileNames))
        imgSeqFileNames{imgIdx+1} = name; 
        imgIdx = imgIdx + 1;
        continue;
    end
        
    %check for match with camera model and subject matter
    if ~isempty(regexp(nameComps{1}, camModel, 'once')) 
        if length(nameComps)>1 && ~isempty(regexp(nameComps{2}, subjTag, 'once')) ...
                               && isempty(regexp(nameComps{2}, subjExcl, 'once'))
            imgSeqFileNames{imgIdx+1} = name; 
            imgIdx = imgIdx + 1;
        end
    end
        
end

imgSeqFileNames = imgSeqFileNames(1:imgIdx);

if isempty(imgSeqFileNames)
    error('Image sequence cannot be found at %s', fullDirPath)
end

nImgs = length(imgSeqFileNames);


end