function colors=som_colorcode(m, colorcode, scaling)

%SOM_COLORCODE Calculates a heuristic color coding for the SOM grid
%
% colors = som_colorcode(m, colorcode, scaling) 
%
%  Input and output arguments ([]'s are optional):
%   m           (struct) map or topol struct
%               (cell array) of form {str,[m1 m2]} where 
%                        str = 'hexa' or 'rect' and [m1 m2] = msize
%               (matrix) size N x 2, unit coordinates 
%   [colorcode] (string) 'rgb1' (default),'rgb2','rgb3','rgb4','hsv'  
%   [scaling]   (scalar) 1=on (default), 0=off. Has effect only
%                        if m is a Nx2 matrix of coordinates: 
%                        controls whether these are scaled to 
%                        range [0,1] or not.
%
%   colors      (matrix) size N x 3, RGB colors for each unit (or point)
%
% The function gives a color coding by location for the map grid 
% (or arbitrary set of points). Map grid coordinates are always linearly 
% normalized to a unit square (x and y coordinates between [0,1]), except
% if m is a Nx2 matrix and scaling=0. In that case too, the coordinates
% must be in range [0,1].
% 
% Following heuristic color codings are available:
%
%  'rgb1' slice of RGB-cube so that       green - yellow
%         the corners have colors:          |       |
%                                         blue  - magenta
%
%  'rgb2' slice of RGB-cube so that       red   - yellow
%         the corners have colors:          |       |
%                                         blue  - cyan   
%
%  'rgb3' slice of RGB-cube so that   mixed_green - orange
%         the corners have colors:          |        |
%                                     light_blue  - pink 
%
%  'rgb4' has 'rgb1' on the diagonal + additional colors in corners
%         (more resolution but visually strongly discontinuous) 
%
%  'hsv'  angle and radius from map centre are coded by hue and 
%         intensity (more resoluton but visually discontinuous)
%
% See also SOM_CPLANE, SOM_SHOW, SOM_CLUSTERCOLOR, SOM_KMEANSCOLOR, 
%          SOM_BMUCOLOR.

% Contributed to SOM Toolbox 2.0, February 11th, 2000 by Johan Himberg
% Copyright (c) by Johan Himberg
% http://www.cis.hut.fi/projects/somtoolbox/

% Version 2.0 Johan 140799 

%%% Check arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

error(nargchk(1, 3, nargin));   % check no. of input args is correct

%% Check m: map, topol, cell or data?

if vis_valuetype(m,{'nx2'}),
  p=m;  % explicit coordinates
  
else
  
  % map, topol, cell
  
  [tmp,ok,tmp]=som_set(m);
  if isstruct(m) & all(ok)
    switch m.type
    case 'som_topol'              % topol 
      msize=m.msize;
      lattice=m.lattice;
    case 'som_map'   
      msize=m.topol.msize;        % map
      lattice=m.topol.lattice;
    otherwise
      error('Invalid map or topol struct.');
    end

  % cell  
    
  elseif iscell(m) & vis_valuetype(size(m),{[1 2]}),
    if vis_valuetype(m{2},{[1 2]}) & vis_valuetype(m{1},{'string'}),
      lattice=m{1};    
      msize=m{2}; 
    else
      error('Invalid map size information.');
    end
  end

  %% Check map parameters
 
  switch lattice                   % lattice  
  case 'hexa' 
    ;
  case 'rect'
    ;
  otherwise
    error('Unknown lattice type');
  end
  
  if length(msize)>2                % dimension
    error('Only 2D maps allowed!');
  end
  
                                     
  % Calculate coordinates 
  p=som_unit_coords(msize,lattice,'sheet');

  % Set scaling to 1 as it is done always in this case
  scaling=1;   
end

% Check colorcode

if nargin < 2 | isempty(colorcode),
  colorcode='rgb1';
end
if ~ischar(colorcode)
  error('String value for colorcode mode expected.');
else
 switch colorcode
 case { 'rgb1', 'rgb2', 'rgb3' , 'rgb4' ,'hsv'}
  otherwise
    error([ 'Colorcode mode ' colorcode ' not implemented.']);
  end
end

% Check scaling

if nargin < 3 | isempty(scaling) 
  scaling=1;
end

if ~vis_valuetype(scaling,{'1x1'})
  error('Scaling should be 0 (off) or 1 (on).');
end

%% Action %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% scale coordintes between [0,1]

if scaling  
  n=size(p,1);
  mn=min(p);
  e=max(p)-mn;
  p=(p-repmat(mn,n,1))./repmat(e,n,1);
elseif sum(p(:,1)>1+p(:,1)<0+p(:,2)>1+p(:,2)<0),  
  error('Coordinates out of range [0,1].');
end

switch colorcode 
case 'rgb1'
  h(:,1)=p(:,1);
  h(:,2)=1-p(:,2);
  h(:,3)=p(:,2);
case 'rgb2'
  h(:,1)=p(:,1);
  h(:,2)=1-p(:,2);
  h(:,3)=1-p(:,1);
case 'rgb3'
  h(:,1)=p(:,1);
  h(:,2)=.5;
  h(:,3)=p(:,2);
case 'rgb4'  
 p=rgb4(p);
 h(:,1)=p(:,1);
 h(:,2)=1-p(:,2);
 h(:,3)=p(:,3);
case 'hsv'
  munits = n;
  Hsv = zeros(munits,3);
  for i=1:n, 
    dx = .5-p(i,1);
    dy = .5-p(i,2);
    r = sqrt(dx^2+dy^2);
    if r==0, 
      h=1; 
    elseif dx==0, 
      h=.5; %h=ay; 
    elseif dy==0, 
      h=.5; %h=ax; 
    else 
      h = min(abs(.5/(dx/r)),abs(.5/(dy/r))); 
    end
    
    if r==0, 
      angle = 0; 
    else 
      angle = acos(dx/r); 
      if dy<0, 
	angle = 2*pi-angle; 
      end
    end
    
    Hsv(i,1) = 1-sin(angle/4);
    Hsv(i,2) = 1;
    Hsv(i,3) = r/h; 
    h = hsv2rgb(Hsv);
  end
end


%% Build output %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

colors=h;

%% Subfunctions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% juha %%%%

function p=rgb4(coord)

for i=1:size(coord,1);
 p(i,:)=get_coords(coord(i,:))';
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function coords=get_coords(coords)

%GET_COORDS
%
% get_coords(coords)
%
% ARGUMENTS
%
% coords (1x2 or 2x1 vector) coords(1) is an x-coordinate and coords(2)
%                            y-coordinate.
%
%
% RETURNS
%
% coords (3x1 vector) x,y and z-coordinates.
%

if ~(all(size(coords) == [1 2]) | all(size(coords) == [2 1]))
  error('Argument ''coords'' must be an 2x1 or 1x2 vector.');
end

if all(size(coords) == [1 2])
  coords=coords';
end

if any(coords > 1) any(coords < 0)
  error('Coordinates must lay inside the interval [0,1].');
end

if coords(1) <= 1/(sqrt(2)+1),
  if coords(2) <= line3(coords(1))
    coords=coords_in_base(4,coords);
  elseif coords(2) <= line2(coords(1))
    coords=coords_in_base(1,coords);
  else
    coords=coords_in_base(2,coords);
  end
elseif coords(1) <= sqrt(2)/(sqrt(2)+1)
  if coords(2) <= line1(coords(1))
    coords=coords_in_base(3,coords);
  elseif coords(2) <= line2(coords(1))
    coords=coords_in_base(1,coords);
  else
    coords=coords_in_base(2,coords);
  end
else
  if coords(2) <= line1(coords(1)),
    coords=coords_in_base(3,coords);
  elseif coords(2) <= line4(coords(1))
    coords=coords_in_base(1,coords);
  else
    coords=coords_in_base(5,coords);
  end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function coords=coords_in_base(base_no,coords)

A=[0;1/(sqrt(2)+1)];
E=[1;1];
F=[0;0];
G=[1;0];
H=[0;1];

const=1+1/sqrt(2);

switch base_no
  case 1
    x=(coords-A)*const;
    coords=[(1/sqrt(2))*(x(1)-x(2));0.5*(x(1)+x(2));0.5*(x(1)+x(2))];
  case 2
    x=(coords-H)*const;
    coords=[0;x(1);1+x(2)];
  case 3
    x=(coords-G)*const;
    coords=[1;1+x(1);x(2)];
  case 4
    x=(coords-F)*const;
    coords=[0.5+(1/sqrt(2))*(x(1)-x(2));...
            0.5-(1/sqrt(2))*(x(1)+x(2));... 
            0];
  case 5
    x=(coords-E)*const;
    coords=[0.5+(1/sqrt(2))*(x(1)-x(2));...
            0.5-(1/sqrt(2))*(x(1)+x(2));...      
            1];
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function y=line1(x)
  
y = x-1/(sqrt(2)+1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function y=line2(x)

y = x+1/(sqrt(2)+1);
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function y=line3(x)

y = -x+1/(sqrt(2)+1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function y= line4(x)

y = -x+(2*sqrt(2)+1)/(sqrt(2)+1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
