function points_s = eq_point_set_polar(dim,N,varargin)
%EQ_POINT_SET_POLAR Center points of regions of an EQ partition
%
%Syntax
% points_s = eq_point_set_polar(dim,N,options);
%
%Description
% POINTS_S = EQ_POINT_SET_POLAR(dim,N) does the following:
% 1) uses the recursive zonal equal area sphere partitioning algorithm to
% partition S^dim (the unit sphere in dim+1 dimensional space) into N regions
% of equal area and small diameter, and
% 2) sets POINTS_S to be an array of size (dim by N), containing the center
% points of each region. Each column of POINTS_S represents a point of S^dim,
% in spherical polar coordinates.
%
% The arguments dim and N must be positive integers.
%
% POINTS_S = EQ_POINT_SET_POLAR(dim,N,'offset','extra') uses experimental extra
% offsets for S^2 and S^3 to try to minimize energy. If dim > 3, extra offsets
% are not used.
%
% POINTS_S = EQ_POINT_SET_POLAR(dim,N,extra_offset) uses experimental extra
% offsets if extra_offset is true or non-zero.
%
%Notes
% Each region is defined as a product of intervals in spherical polar
% coordinates. The center point of a region is defined via the center points
% of each interval, with the exception of spherical caps and their descendants,
% where the center point is defined using the center of the spherical cap.
%
% For more details on options, see HELP PARTITION_OPTIONS.
%
%Examples
% > points_s = eq_point_set_polar(2,4)
% points_s =
%          0    1.5708    4.7124         0
%          0    1.5708    1.5708    3.1416
%
% > size(points_s)
% ans =
%      2     4
%
%See also
% PARTITION_OPTIONS, EQ_POINT_SET, EQ_REGIONS

% Copyright 2004-2005 Paul Leopardi for the University of New South Wales.
% $Revision 1.10 $ $Date 2005-06-01 $
% Function changed name from s2x to polar2cart
% Function changed name from x2s2 to cart2polar2
% Optimize running time:
%   use slice assignments
%   trade space for time by using a cache
% Documentation files renamed
% $Revision 1.00 $ $Date 2005-02-13 $
%
% For licensing, see COPYING.
% For references, see AUTHORS.
% For revision history, see CHANGELOG.

%
% Check number of arguments
%
narginchk(2,4);
%
% dim is the number of dimensions
% N is the number of regions
%
% If the option 'offset' is 'extra', then use experimental extra offsets
% for S^2 and S^3 regions to try to minimize energy.
% The default is not to use extra offsets.
%
pdefault.extra_offset =  false;
if nargin < 3
    extra_offset = pdefault.extra_offset;
else
    popt = partition_options(pdefault, varargin{:});
    extra_offset = popt.extra_offset;
end
%
% Extra offset does not currently work for dim > 3,
% so quietly ignore this option in this case.
% Note that this also affects recursive calls to lower dimensions.
%
if dim > 3
    extra_offset = false;
end
%
% Check that dim and N are positive integers.
%
if ~( isnumeric(dim) && (dim >= 1) && (dim == floor(dim)) ) || ...
   ~( isnumeric(N) && (N >= 1) && (N == floor(N)) )
    fprintf('Usage: eq_point_set_polar(dim, N)\n');
    error('The arguments dim and N must be positive integers.');
end

if N == 1
    %
    % We have only one region, which must be the whole sphere.
    %
    points_s = zeros(dim,1);
    return;
end
%
% Start the partition of the sphere into N regions by partitioning
% to caps defined in the current dimension.
%
[a_cap, n_regions] = eq_caps(dim,N);
%
% a_cap is an increasing list of angles of the caps.
%
if dim == 1
    %
    % We have a circle and a_cap is an increasing list of angles of sectors,
    % with a_cap(k) being the cumulative arc length 2*pi/k.
    % The points are placed half way along each sector.
    %
    points_s = a_cap - pi/N;
    %
else
    %
    % We have a number of zones: two polar caps and a number of collars.
    % n_regions is the list of the number of regions in each zone.
    %
    n_collars = size(n_regions,2)-2;
    use_cache = dim >= 2;
    if use_cache
        cache_size = floor(n_collars/2);
        cache = cell(1,cache_size);
    end
    %
    % Start with the 'centre' point of the North polar cap.
    % This is the North pole.
    %
    points_s = zeros(dim,N);
    point_n = 2;
    %
    % Determine the 'centre' points for each collar.
    %
    if extra_offset && (dim == 3)
        R = eye(3);
    end
    if dim == 2
        offset = 0;
    end
    for collar_n = 1:n_collars
        %
        % a_top is the colatitude of the top of the current collar.
        %
        a_top = a_cap(collar_n);
        %
        % a_bot is the colatitude of the bottom of the current collar.
        %
        a_bot = a_cap(1+collar_n);
        %
        % n_in_collar is the number of regions in the current collar.
        %
        n_in_collar = n_regions(1+collar_n);
        %
        % The top and bottom of the collar are small (dim-1)-spheres,
        % which must be partitioned into n_in_collar regions.
        % Use eq_point_set_polar recursively to partition
        % the unit (dim-1)-sphere.
        % points_1 is the resulting list of points.
        %
        if use_cache
            twin_collar_n = n_collars-collar_n+1;
            if twin_collar_n <= cache_size && ...
                size(cache{twin_collar_n},2) == n_in_collar
                points_1 = cache{twin_collar_n};
            else
                points_1 = eq_point_set_polar(dim-1,n_in_collar,extra_offset);
                cache{collar_n} = points_1;
            end
        else
            points_1 = eq_point_set_polar(dim-1,n_in_collar,extra_offset);
        end
        %
        if extra_offset && (dim == 3) && (collar_n > 1)
            %
            % (Experimental)
            % Rotate 2-spheres to prevent alignment of north poles.
            %
            R = s2_offset(points_1)*R;
            points_1 = cart2polar2(R*polar2cart(points_1));
        end
        %
        % Given points_1, determine the 'centre' points for the collar.
        % Each point of points_1 is a 'centre' point on the (dim-1)-sphere.
        %
        % Angular 'centre' point;
        % The first angles are those of the current 'centre' point
        % of points_1, and the last angle in polar coordinates is the average of
        % the top and bottom angles of the collar,
        %
        a_point = (a_top+a_bot)/2;
        %
        point_1_n = 1:size(points_1,2);
        %
        if dim == 2
            %
            % The (dim-1)-sphere is a circle
            %
            points_s(1:dim-1,point_n+point_1_n-1) = mod(points_1(:,point_1_n)+2*pi*offset,2*pi);
            %
            % Given the number of sectors in the current collar and
            % in the next collar, calculate the next offset.
            % Accumulate the offset, and force it to be a number between 0 and 1.
            %
            offset = offset + circle_offset(n_in_collar,n_regions(2+collar_n),extra_offset);
            offset = offset - floor(offset);
        else
            points_s(1:dim-1,point_n+point_1_n-1) = points_1(:,point_1_n);
        end
        %
        points_s(dim, point_n+point_1_n-1) = a_point;
        point_n = point_n + size(points_1,2);
    end
    %
    % End with the 'centre' point of the bottom polar cap.
    %
    points_s(:,point_n) = zeros(dim,1);
    points_s(dim,point_n) = pi;
end
%
% end function
