%                               431-400 Year Long Project 
%                           LA1 - Medical Image Processing 2003
%  Supervisor     :  Dr Lachlan Andrew
%  Group Members  :  Alister Fong    78629   a.fong1@ugrad.unimelb.edu.au
%                    Lee Siew Teng   102519  s.lee1@ugrad.unimelb.edu.au
%                    Loh Jien Mei    103650  j.loh1@ugrad.unimelb.edu.au
%
%  File and function name : plot_circle.m
%  Version                : 4.0
%  Date of completion     : 20 August 2003   
%  Written by    :   Alister Fong    78629   a.fong1@ugrad.unimelb.edu.au
% 
% Inputs :
%     X               -   The X coordinates of the center of this circle
%     Y               -   The Y coordinates of the center of this circle
%     Radius          -   The radius of this circle >= 0
%     intervals (optional) - The number of evenly spaced points along the X axis 
%                            inclusive of the start and end coordinates
%                           (needed by 'interval' algorithm)
%     algorithm (optional) - Allows the choice of the following algorithms
% 							= 'angle' (default)
%                                 Calculates the node points by its angle
% 							= 'interval'
%                                  Takes the number of intervals and spaces the 
%                                  X coordinates out according to the integer 
%                                  value of intervals 
% 							= 'bresenham'
%                                  Uses the "Bresenham's incremental circle algorithm" 
%                                  on Page 84-85, Chapter 2, "Procedural Elements for 
%                                  Computer Graphics, Second Edition" by David F. Rogers,
%                                  UniM Engin 006.6 ROGE,
%                                  Produces a digital integer approximation of a circle 
%                                  that is suitable for plotting a circle in a matrix
% 							= 'bresenhamSolid'
%                                  Uses the "Bresenham's incremental circle algorithm" 
%                                  that have been modified to produce a solid circle instead
%                                  instead of the circumference
%
% Outputs :
%     output_coord    -   Results in a [M x 2] matrix :
%                         The coordinates desired: 
%                                      X coordinates are output_coord(:,1) and 
%                                      Y coordinates are output_coord(:,2)
%                         and the first and last coordinates are the same to 
%                         ensure that a complete closed circle is formed
% 
% Description :
%     To calculate the coordinates needed to draw a circle given the details of the
% circle, for use by the 'plot' function
% 
% Usage >> output_coord = plot_circle(X,Y,Radius);    or
%          output_coord = plot_circle(X,Y,Radius,intervals,algorithm);
%          plot(output_coord(:,1),output_coord(:,2),'r*-');
% 
%       >> output_coord = plot_circle(X,Y,Radius,'bresenham');
%          output_image = zeros(500);
%          [M,N] = size(output_coord);
%          for q = 1:1:M
%              output_image(output_coord(q,1),output_coord(q,2)) = 1;
%          end
%          imshow(output_image);

function output_coord = plot_circle(X,Y,Radius,varargin)
outputX = [];
outputY = [];
temp_mod = 1;
cal_mode = 'angle'; %default
intervals = NaN;

% =============================================================
% Check optional inputs
% =============================================================
if (length(varargin) > 0)
    for a = 1:1:length(varargin)
        if isstr(varargin{a}) == 1
            if ((strcmp(varargin{a},'angle') == 1)|...
                (strcmp(varargin{a},'interval') == 1)|...
                (strcmp(varargin{a},'bresenham') == 1)|...
                (strcmp(varargin{a},'bresenhamSolid') == 1)...
               )
                cal_mode = varargin{a};
            end
        elseif isfinite(varargin{a}) == 1
            intervals = varargin{a};    
        else
            error('Invalid arguments');
        end
    end
end

% =============================================================
% Initialization of 'interval'
% =============================================================
if strcmp(cal_mode,'interval') == 1
	% Satisfies requirement for calculation by the given intervals
    if isnan(intervals) == 1
        error('No interval given');
    end
	temp_mod = mod(intervals,2);
	interval = (intervals - temp_mod) / 2;
	interval_size = (Radius+Radius)/intervals;
	valueX = 0;
	if temp_mod == 1
		outputX = [0];
        outputY = [Radius];
    else
        valueX = (-1/2)*interval_size;
	end       
    cal_mode = 'interval';
end

% =============================================================
% Calculate the 1st quardrant 
% =============================================================
	% ************************************************************
	% 	by the angle, scaled by the given radius
	% ************************************************************
if strcmp(cal_mode,'angle') == 1
	increment_angle = pi*(1/Radius);
	curr_angle = pi/2;
	loop=0;
	while curr_angle>0   
	loop=loop+1;
        outputX = [outputX(:);sqrt(Radius^2-(Radius*sin(curr_angle))^2)];
        outputY = [outputY(:);sqrt(Radius^2-(Radius*cos(curr_angle))^2)];
        curr_angle = curr_angle-increment_angle;
	end
	outputX = [outputX(:);Radius];
	outputY = [outputY(:);0];
elseif strcmp(cal_mode,'interval') == 1
	% ************************************************************
	% 	by the given x-interval
	% ************************************************************
	valueX = valueX + interval_size;
	while valueX < Radius 
        outputX = [outputX(:);valueX];
        outputY = [outputY(:);sqrt((Radius*Radius)-(valueX*valueX))];
        valueX = valueX + interval_size;
	end
    outputX = [outputX(:);Radius];
    outputY = [outputY(:);0];
elseif (strcmp(cal_mode,'bresenham') == 1) || (strcmp(cal_mode,'bresenhamSolid') == 1)
    X = round(X);
    Y = round(Y);
    Radius = round(Radius);
	% ************************************************************
    % Taken from Chapter 2, Page 84-85, David F. Rogers, 
    % "Procedural Elements for Computer Graphics,Second Edition"
	% ************************************************************
    x_i = 0;
    y_i = Radius;
    theta_i=2*(1-Radius);
    Limit = 0;
    while y_i >= Limit
        % Set Pixel
        if (strcmp(cal_mode,'bresenham') == 1) 
            % Plot the circumference
            outputX = [outputX(:);x_i];
            outputY = [outputY(:);y_i];
        elseif (strcmp(cal_mode,'bresenhamSolid') == 1)
            % Create a solid circle
            tempY = [0:1:y_i]';
            tempX = tempY;
            tempX(:) = x_i;
            outputX = [outputX(:);tempX];
            outputY = [outputY(:);tempY];
        else
            error('Invalid option');
        end
        % determine if case 1 or 2, 4 or 5, or 3
        if theta_i < 0
            delta = 2*(theta_i + y_i) - 1;
            % determine whether case 1 or 2
            if delta <= 0
                % move horizontally
                x_i = x_i + 1;
                theta_i = theta_i + (2*x_i) + 1;
            else
                % move diagonally
                x_i = x_i + 1;
                y_i = y_i - 1;
                theta_i = theta_i + (2*(x_i - y_i)) + 2;
            end
        elseif theta_i > 0
            delta_prime = 2*(theta_i - x_i) -1;
            % determine whether case 4 or 5
            if delta_prime <= 0
                % move diagonally
                x_i = x_i + 1;
                y_i = y_i - 1;
                theta_i = theta_i + (2*(x_i - y_i)) + 2;
            else
                % move vertically
                y_i = y_i - 1;
                theta_i = theta_i - (2*y_i) + 1;
            end
        elseif theta_i == 0
                % move diagonally
                x_i = x_i + 1;
                y_i = y_i - 1;
                theta_i = theta_i + (2*(x_i - y_i)) + 2;          
        end
    end
end
% =============================================================
% Calculate the 2nd quardrant
% =============================================================
length_outputX = length(outputX);
if temp_mod == 1
	% Avoids duplicate coordinates
	outputX = [outputX([length_outputX:-1:2])*(-1);outputX(:)];
	outputY = [outputY([length_outputX:-1:2]);outputY(:)];
else
    outputX = [outputX([length_outputX:-1:1])*(-1);outputX(:)];
	outputY = [outputY([length_outputX:-1:1]);outputY(:)];
end

% =============================================================
% Calculate the 3rd and 4th quardrant and to close the loop
% =============================================================
length_outputY = length(outputY)-1;
outputX = [outputX(:);outputX([length_outputY:-1:1])];
outputY = [outputY(:);outputY([length_outputY:-1:1])*(-1)];
% =============================================================
% Shift the circle to the desired center
% =============================================================
outputX = outputX+X;
outputY = outputY+Y;
output_coord = [outputX,outputY];

% If a solid is asked for make sure there are no duplicates
if (strcmp(cal_mode,'bresenhamSolid') == 1)
    output_coord = unique(output_coord,'rows');
end