function [ FittedParticle, layers ] = pyramidAdaFitting2D(Particles)

% setup pyramid, determine the pyramid height or the number of layers
N = numel(Particles);
isPow2 = mod(log2(N),1);
if (isPow2 == 0)
    height = floor(log2(N));        
else
    height = floor(log2(N))+1;      
end

disp(['There are ' num2str(height) ' layers in pyramid.']);    

layers(height).node = [];   % store each layer data in the pyramid

% in each layer, fuse all the pairs of particles
for it_layer = 1:height;
    
    ls = zeros(1,length(Particles));
    for l = 1:length(Particles)
        ls(1,l)=size(Particles{l}.points,1);
    end

    [~,I] = sort(ls(:));
    I((mod(length(I),2)+1):2:end) = I(fliplr((mod(length(I),2)+1):2:end));

    Particles = Particles(I);    
    
    disp(['layer #' num2str(it_layer) ' started ! ']);    
    tic;
    to = 1:2:numel(Particles);          % odd particles
    from = 2:2:numel(Particles);        % even particles    
    tmpParticles = cell(1,numel(to));   % initialize 
    
    %if odd number of particles: move the last one, one layar up.
    if numel(to) > numel(from)
        tmpParticles{numel(to)} = Particles{to(end)};
    end
    
    len = numel(from);                  % total number of pairs in current 
                                        % layer
    node(len) = struct();               % preallocate memory for nodes in 
                                        % current layer    
                                        
    % fitting a single pair
    parfor i = 1:len

        S = Particles{to(i)};
        M = Particles{from(i)};

        node(i).left = M;               % left particle
        node(i).right = S;              % right particle
        
        % pair registration
        [~, tmpParticles{i}, ~, ~, max_val] = pairFitting(M, S);        

        node(i).merge = tmpParticles{i};% fused particle
        node(i).score = max_val;        % the score of registration
        
    end
    
    % save each layer seperately
    if len~=0
        layers(it_layer) = struct('node', node);
        save(['test/layer' num2str(it_layer)], 'node');
    end
    
    % clear current node
    clearvars node;
    
    % random permutate the particles to avoid thinning the right flank.
    permids = randperm(length(tmpParticles));
    Particles = tmpParticles(permids);
    
    % uncomment the following to stop shufflling of particles at each layer
    %Particles = tmpParticles;
    
    a = toc;
    disp(['layer #' num2str(it_layer) '... done in ' num2str(a) ' seconds']);    

end

% save result to disk
save('test/pyramid', 'layers');
FittedParticle = Particles{1};

disp('Adapted Pyramid registration ... done');

end