classdef TestImgGen < handle
    %TESTIMGGEN Colection of methods for generating test patterns
    
    
    properties
        TestImgSize
        
        ClearField_TestPattern
        DarkField_TestPattern
        CenterCross_TestPattern
        
        Dots_TestPattern
        Grid_TestPattern
        Checkerboard_TestPattern
        
        spacing
        brushRadius
    end
    properties (Access = private)
        Cx
        Cy
        Cr
        C
        
        
    end
    
    methods
        function obj = TestImgGen(inputArg1,inputArg2,inputArg3)
            %TESTIMGGEN Construct an instance of this class
            if nargin > 0
                obj.TestImgSize = inputArg1;
            end
            if nargin > 1
                obj.testPatterns(inputArg1,inputArg2,inputArg3,1);
            end
        end
        
        function imOut = testClear(obj)
            imOut = ones(obj.TestImgSize)*255;
            obj.ClearField_TestPattern = imOut;
        end
        
        function imOut = testDark(obj)
            imOut = zeros(obj.TestImgSize);
            obj.DarkField_TestPattern = imOut;
        end
        
        function [dotImg, gridImg] = testPatterns(obj,TestImgSize,spacing,brushRadius,originSquareColor)
            obj.TestImgSize = TestImgSize;
            obj.testClear();
            obj.testDark();
            dotImg = obj.testDots([obj.TestImgSize], spacing, brushRadius);
            gridImg = obj.testGrid([obj.TestImgSize], spacing, brushRadius);
            checkerborardImg = obj.testCheckerboard([obj.TestImgSize], spacing, originSquareColor);
            
            obj.Dots_TestPattern = dotImg;
            obj.Grid_TestPattern = gridImg;
            obj.Checkerboard_TestPattern = checkerborardImg;
            obj.spacing = spacing;
            obj.brushRadius = brushRadius;
        end
        
        function imOut = testGrid(obj,size_img,spacing,radius)
            imOut = zeros(size_img(1:2));
            % get coordinates round(linspace)
            X = obj.imgFindStep(spacing(2),size_img(2),radius);
            Y = obj.imgFindStep(spacing(1),size_img(1),radius);
            % draw lines
            r = radius - 1;
            imOut(:,X + [-r:r]') = 255;
            imOut(Y + [-r:r]',:) = 255;
            % copy RGB
            imOut = repmat(imOut,1,1,size_img(3));
        end
        
        function imOut = testDots(obj,size_img,spacing,radius)
            % https://matlab.fandom.com/wiki/FAQ#How_do_I_create_a_circle.3F
            imOut = zeros(size_img(1:2));
            % get coordinates round(linspace)
            X = obj.imgFindStep(spacing(2),size_img(2),radius);
            Y = obj.imgFindStep(spacing(1),size_img(1),radius);
            % generate meshgrid
            [obj.Cx,obj.Cy]= meshgrid(X,Y);
            obj.Cr = radius;
            
            [columnsInImage, rowsInImage] = meshgrid(1:size_img(2), 1:size_img(1));
            % covert to vetor [y1,x1; y2,x2;...]
            C = [obj.Cx(:),obj.Cy(:)];
            % paint each circle
            for i = 1:size(C,1)
                circlePixels = (rowsInImage - C(i,2)).^2 ...
                    + (columnsInImage - C(i,1)).^2 < radius.^2;
                imOut(circlePixels) = 256;
            end
            % copy to RGB
            imOut = repmat(imOut,1,1,size_img(3));
        end
        
        function [imOut,X,Y] = testCheckerboard(obj, size_img, spacing, originSquareColor)
            imOut2 = zeros(size_img(1:2));
            % get coordinates round(linspace)
            X = obj.imgFindStep(spacing(2),size_img(2),1);
            Y = obj.imgFindStep(spacing(1),size_img(1),1);
            
            % horizontal stripe 0000 1111 0000 1111
            xx = ones(1,size_img(2)) * ~originSquareColor;
            U = X(2:2:length(X));
            L = X(1:2:length(X)-1);
            
            for i = 1:length(U)
                xx(L(i):U(i)-1) = ~xx(L(i):U(i)-1);
            end
             % horizontal stripe 0000 1111 0000 1111
            yy = ones(size_img(1),1) ;
            U = Y(2:2:length(Y));
            L = Y(1:2:length(Y)-1);
            
            for i = 1:length(U)
                yy(L(i):U(i)-1) = ~yy(L(i):U(i)-1);
            end
            
            % combine horizontal & vertical stripes
            imOut = xor(xx,yy).* 255;
            
            if length(size_img) > 2
                 % copy RGB
                imOut = repmat(imOut,1,1,size_img(3)); 
            end    
            
            
            
        end
        
        function [X2,Y2,cX,cY, imgOut]= CheckerboardGridAlignPoints(obj,cX, cY, X,Y,testCheckerboard)
            %cX,cY position of corner to preserve , X,Y = corners,
            %testCheckerboard = grid image
            
            %copy corner to imgOut
            imgOut = zeros(size(testCheckerboard));
            for i = 1:length(cX)
                imgOut(Y(cY(i)-1):Y(cY(i)+1)-1,X(cX(i)-1):X(cX(i)+1)-1,:) = testCheckerboard(Y(cY(i)-1):Y(cY(i)+1)-1,X(cX(i)-1):X(cX(i)+1)-1,:);
            end
            
            % adjust X,Y to subpixel accuracy point, 2:end-1 => corner
            [X2, Y2] = meshgrid(X(2:end-1)-0.5,Y(2:end-1)-0.5);
            cX = cX-1;
            cY = cY-1;
            
            
        end
        
        function vecOut = imgFindStep(~,stepIn,distanceIn,offsetIn)
            % return vector of coordinates linearly spaced (rounded to descrete values)
            % step upper bound
            if stepIn > 180; stepIn = 180;end
            % numer of steps
            N = round((distanceIn-offsetIn*2)/stepIn);
            % round linspace between 1 and distanceIn, uneven spacing (int)
            vecOut = round(linspace(offsetIn,distanceIn-offsetIn+1,N+1));
        end
        
        function c = check_mod(~,im_size,c,s)
            fprintf('IM_test_image : Wrong %s grid size, adjusting from: %d ',s,c);
            while  mod(im_size,c)
                c=c+1;
            end
            fprintf('to %d px\n',c);
        end
        
        
        function imgOut = testGridImg(obj,size_img,hor_count,vert_count)
            line_width = 4;
            border_width = 1.5*line_width;
            vert_count = obj.check_mod(size_img(1)-border_width*2+line_width,vert_count,'vertical');
            hor_count = obj.check_mod(size_img(2)-border_width*2+line_width,hor_count,'horizontal');
            
            border = zeros(size_img(1:2));
            border(border_width+1:end-border_width,border_width+1:end-border_width) = 1;
            
            rep_pattern = zeros((size_img(1)-border_width*2+line_width)/vert_count,(size_img(2)-border_width*2+line_width)/hor_count);
            rep_pattern(line_width+1:end,line_width+1:end) = 1;
            
            rep = repmat(rep_pattern,vert_count,hor_count);
            rep2 = zeros(size_img(1:2));
            rep2(border_width+1-line_width:end-border_width,border_width+1-line_width:end-border_width) = rep;
            imgOut = (border&rep2).*256;
            imgOut(:,:,2)= imgOut(:,:,1);
            imgOut(:,:,3)= imgOut(:,:,1);
            
        end
    end
end

