function [pre] = MLS_precompute(p_i,V,alpha,size_of_img,type)
% PRECOMPUTATION

%% common for all  MLS tranformation methods
% for each eval point v all control points need to be looped

% new variables
pre.w_i = zeros(size(p_i,1),size(V,1));
pre.sum_w_i = zeros(size(V,1),1);
pre.p_ast = zeros(size(V,1),2);
pre.Similarity = zeros(2*size(p_i,1),2*size(V,1));
%pre.Rigid = zeros(2*size(p_i,1),2*size(V,1));

%pre = cell(size_of_img);
for eval = 1:size(V,1)
    v = V(eval,:);
    
    if isdeployed
        fprintf("deployed")
    end
    % weights w_i = 1/length_of_vect(p_i-v)^(2alpha)
%     aaa = repmat(v,size(p_i,1),1);
%     aaaa = p_i-aaa;
%     w_i = ones(size(p_i,1),1) ./ (sqrt(sum(( p_i-repmat(v,size(p_i,1),1) ).^2,2)).^(2*alpha));
    if all(any(p_i==v))
        if any((v-0.0001) < 1) 
            p_i(p_i==v) = p_i(p_i==v) + 0.0001;
        else 
             p_i(p_i==v) = p_i(p_i==v) - 0.0001;
        end
        fprintf('Bulls eye, you hit control point\n')   
    end
    w_i = ones(size(p_i,1),1) ./ (sqrt(sum(( p_i-repmat(v,size(p_i,1),1) ).^2,2)).^(2*alpha));
   
        
        % p? and q? are weighted centroids.
   
    sum_w_i = sum(w_i); 
   
    p_ast = sum([w_i,w_i].*p_i, 1) ./ sum_w_i;
    if any(any(isnan(p_ast)))
        assignin('base','p_ast',p_ast)
        assignin('base','w_i',w_i)
        assignin('base','v',v)
         w_i = ones(size(p_i,1),1) ./ (sqrt(sum(( p_i-repmat(v,size(p_i,1),1) ).^2,2)).^(2*alpha));
         sum_w_i = sum(w_i); 
        
        p_ast = sum([w_i,w_i].*p_i, 1) ./ sum_w_i;
        assignin('base','p_ast2',p_ast)
        assignin('base','w_i2',w_i)
    end
    
    % p^_i for substitution
    p_hat_i = p_i - repmat(p_ast,size(p_i,1),1);
    
    
    
    if strcmp(type,'Affine') || strcmp(type,'All')        
        %pre{v(1),v(2)}.Affine = precompute_Affine(p_hat_i,p_ast,w_i,v);
    end
    if strcmp(type,'Similarity') || strcmp(type,'Rigid') || strcmp(type,'All')
        %[pre{v(1),v(2)}.Similarity, pre{v(1),v(2)}.Rigid] = precompute_SimilarityAndRigid(p_hat_i,p_ast,w_i,v);
    end
    % needed for q
    %pre{v(1),v(2)}.w_i = w_i;
    %pre{v(1),v(2)}.sum_w_i = sum_w_i;
    
    % needed for Rigid deform
    %pre{v(1),v(2)}.p_ast = p_ast;
    
    
    % new pre
    pre.w_i(:,eval) = w_i;
    pre.sum_w_i(eval,1) = sum_w_i;
    pre.p_ast(eval,:) = p_ast;
    
    pre.Affine(:,eval) = precompute_Affine(p_hat_i,p_ast,w_i,v);
    [pre.Similarity(:,2*eval-1:2*eval), pre.Rigid(:,2*eval-1:2*eval)] = precompute_SimilarityAndRigid(p_hat_i,p_ast,w_i,v);
end
end

%% Aj - scalar for each control point p at given evaluation point v
% -> for each v vector (Aj_1;Aj_2;Aj_3;...)
function Affine = precompute_Affine(p_hat_i,p_ast,w_i,v)
% Affine transform precompute
% Single scalar for each control point p -> vector
% ([2,2]-[1,1])*([1;1]*1*[1,1])*[1;1]

s = zeros(2);
for i = 1:length(w_i)
   s = s + (p_hat_i(i,:))' * w_i(i) * p_hat_i(i,:);
end
inv_sum = [s(4) -s(3); -s(2) s(1)]./(s(1)*s(4)-s(3)*s(2));
sum_p_j = sum(p_hat_i,1)';
% inv_sum = -inv(s); %added - 
Affine = zeros(length(w_i),1);
for j = 1:length(w_i)
    Affine(j) = (v-p_ast)*inv_sum*sum_p_j;
end
end

%% Ai - matrix for each control point p at given evaluation point v
% mu_s scalar for each evaluation point v
function [Similarity,Rigid] = precompute_SimilarityAndRigid(p_hat_i,p_ast,w_i,v)
% Similarity transform precompute

mu_s = 0;
for i = 1:length(w_i)
    mu_s = mu_s + w_i(i) * p_hat_i(i,:) * p_hat_i(i,:)';
end

v_p_ast = (v-p_ast);
perpend = (-1)*(perpend_vec(v-p_ast));
Matrix_T = [(v-p_ast); (-1)*(perpend_vec(v-p_ast))]';

%Similarity = zeros(2,2,length(w_i));
%Rigid = zeros(2,2,length(w_i));

Similarity = zeros(2*length(w_i),2);
Rigid = zeros(2*length(w_i),2);
for i = 1:length(w_i)
    A_i_temp = w_i(i) ...
        * [p_hat_i(i,:) ; (-1)*perpend_vec(p_hat_i(i,:))]...
        * Matrix_T;
  
    Similarity(2*i-1:2*i,:) = A_i_temp / mu_s;
    Rigid(2*i-1:2*i,:) = A_i_temp;
end
end
%% support function for precompute_SimilarityAndRigid
% (x,y) -> (-y,x)
function vec = perpend_vec(vec)
temp = vec(1);
vec(1) = (-1)*vec(2);
vec(2) = temp;
end


