% EEG_MATCHCHANS  - find closest channels in a larger EEGLAB chanlocs structure
%                     to channels in a smaller chanlocs structure
% Usage:
%        >> [selchans,distances,selocs] = eeg_matchchans(BIGlocs,smalllocs,'noplot');
% Inputs:
%        BIGlocs    - larger (or equal-sized) EEG.chanlocs structure array
%        smalllocs  - smaller (or equal-sized) EEG.chanlocs structure array
% Optional inputs:
%        'noplot'   - [optional string 'noplot'] -> do not produce plots {default: 
%                     produce illustrative plots of the BIG and small locations}
% Outputs:
%        selchans   - indices of BIGlocs channels closest to the smalllocs channels
%        distances  - vector of distances between the selected BIGlocs and smalllocs chans
%        selocs     - EEG.chanlocs structure array containing nearest BIGlocs channels 
%                     to each smalllocs channel: 1, 2, 3,... n. This structure has
%                     two extra fields: 
%                                    bigchan  - original channel index in BIGlocs
%                                    bigdist  - distance between bigchan and smalllocs chan 
%                     ==> bigdist assumes both input locs have sph_radius 1.
%
% Author: Scott Makeig, SCCN/INC/UCSD, April 9, 2004

% Copyright (C) 2004 Scott Makeig, SCCN/INC/UCSD, smakeig@ucsd.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

% History: began Jan 27, 2004 as selectchans.m(?) -sm

function [selchans,dists,selocs] = eeg_matchchans(bglocs,ltlocs,noplot)

if nargin < 2
  help eeg_matchchans
  return
end
no_plot = 0; % yes|no flag
if nargin > 2 && strcmp(lower(noplot),'noplot')
  no_plot = 1;
end

if ~isstruct(bglocs) || ~isstruct(ltlocs)
   help eeg_matchchans
end

ltchans = length(ltlocs);
bgchans = length(bglocs);
if ltchans > bgchans
  fprintf('BIGlocs chans (%d) < smalllocs chans (%d)\n',bgchans,ltchans);
  return
end
selchans = zeros(ltchans,1);
dists    = zeros(ltchans,1);
bd       = zeros(bgchans,1);
%
%%%%%%%%%%%%%%%%% Compute the distances %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
fprintf('BIG  ltl  Dist\n');
for c=1:ltchans
   for C=1:bgchans
      if ~isempty(ltlocs(c).X) && ~isempty(bglocs(C).X)
        bd(C) = sqrt((ltlocs(c).X/ltlocs(c).sph_radius - bglocs(C).X/bglocs(C).sph_radius)^2 + ...
                    (ltlocs(c).Y/ltlocs(c).sph_radius - bglocs(C).Y/bglocs(C).sph_radius)^2 + ...
                    (ltlocs(c).Z/ltlocs(c).sph_radius - bglocs(C).Z/bglocs(C).sph_radius)^2);
      end
   end
   %
   %%%%%%%%%%%%%%%%% Find the nearest BIGlocs channel %%%%%%%%%%%%%%%%%%%%%%%
   %
   [bd ix] = sort(bd); % find smallest distance c <-> C
   bglocs(1).bigchan = [];
   k=1;
   while ~isempty(bglocs(ix(k)).bigchan) & k<=bgchans % avoid empty channels
     k=k+1;
   end
   if k>bgchans
     fprintf('No match found for smalllocs channel %d - error!?\n',c);
     return % give up - should not reach here!
   end
   while k<length(ix)
     if c>1 && sum(ismember(ix(k),selchans(1:c-1)))>0 % avoid chans already chosen 
        k = k+1;
     else
        break
     end
   end
   if k==length(ix)
      fprintf('NO available nearby channel for littlechan %d - using %d\n',...
                  c,ix(k));
   end
   selchans(c) = ix(k); % note the nearest BIGlocs channel
   dists(c)    = bd(k); % note its distance
   bglocs(ix(k)).bigchan = selchans(c); % add this info to the output
   bglocs(ix(k)).bigdist = dists(c);
   fprintf('.bigchan %4d, c %4d, k %d, .bigdist  %3.2f\n',...
        bglocs(ix(k)).bigchan,c,k,bglocs(ix(k)).bigdist); % commandline printout
end; % c
selocs = bglocs(selchans); % return the selected BIGlocs struct array subset
%
%%%%%%%%%%%%%%%%% Plot the results %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
if ~no_plot
    figure;
    titlestring = sprintf('%d-channel subset closest to %d channel locations',ltchans,bgchans);
    tl=textsc(titlestring,'title');
    set(tl,'fontweight','bold');
    set(tl,'fontsize',15);
    sbplot(7,2,[3 13]);
    hist(dists,length(dists));
    title('Distances between corresponding channels');
    xlabel('Euclidian distance (sph. rad. 1)');
    ylabel('Number of channels');

    sbplot(7,5,[8,35]);
    topoplot(dists,selocs,'electrodes','numbers','style','both');
    title('Distances');
    clen = size(colormap,1);
    sbnull = sbplot(7,2,[10 12])
    cb=cbar;
    cbar(cb,[clen/2+1:clen]);
    set(sbnull,'visible','off')
    
    axcopy; % turn on axcopy
end
