function config = rok_room_generate_convex_hulls (room, config_file, debug)
    % config = ROK_ROOM_GENERATE_CONVEX_HULLS (room, config, debug)
    %
    % Generates convex hulls configuration for a room.
    %
    % Input:
    %  - room = room configuration structure, obtained by
    %    ROK_ROOM_CREATE(), or room configuration filename
    %  - config_file = rectangles configuration INI file
    %  - debug = whether to draw debug figures
    %
    % Output:
    %  - config = convex hulls config file
    %
    % Copyright (C) 2011-2012, Rok Mandeljc <rok.mandeljc@fe.uni-lj.si>
    
    % Load room config, if given as a file
    if ischar(room),
        room = rok_room_create(room);
    end
    
    % Load rectangles config, if given as a file
    config = rok_parse_config_ini(config_file);    
    
    % Default value for debug
    if nargin < 3,
        debug = false;
    end

    % Grid
    [ X, Y ] = ndgrid(room.xVals, room.yVals);

    %% Generate convex hulls for each camera
    % Preallocate
    numLocations = room.nx * room.ny;
    numCameras = numel(config.cameras);
    
    indices = cell(numLocations, numCameras);
    vertices = cell(numLocations, numCameras);
    valid = false(numLocations, numCameras);
    area = zeros(numLocations, numCameras);
    frameWidth = zeros(1, numCameras);
    frameHeight = zeros(1, numCameras);
    
    % Generate
    for c = config.cameras,
        fprintf(1, 'View #%d\n', c);
        tic;
        [ indices(:, c), vertices(:, c), area(:,c), valid(:, c), frameWidth(:, c), frameHeight(:, c) ] = rok_generate_convex_hulls_for_view(room, config, c, X, Y, debug);
        fprintf(1, 'Generated in %f seconds...\n', toc);
    end

    %% Draw coverage
    if debug,
        fig = figure;
        set(fig, 'Name', 'Cell coverage');
        hold on;

        grid on;
        surface( room.xVals, room.yVals, reshape( sum(valid, 2), room.nx, room.ny )' );
        mesh( room.xVals, room.yVals, zeros(room.ny, room.nx) );
        xlabel('X [m]');
        ylabel('Y [m]');
        set(gca, 'View', [90 90]);
    end

    %% Save
    config.frameWidth = frameWidth;
    config.frameHeight = frameHeight;
    
    config.hulls.vertices = vertices;
    config.hulls.indices = indices;
    config.hulls.area = area;
    config.hulls.valid = valid;

    config.room = room;

    %% Store config?
    if nargout < 1,
        [filename, pathname] = uiputfile('config-hulls.mat', 'Save config as');
        if filename ~= 0,
            save(fullfile(pathname, filename), '-struct', 'config');
        end
    end
end


function [ indices, vertices, area, valid, frameWidth, frameHeight ] = rok_generate_convex_hulls_for_view (room, config, c, X, Y, debug)
    % Load camera calibration
    calibrationData = load( rok_format_filename(config.calibration_data_format, 'camera', c) );
    
    % Load image
    I = imread( rok_format_filename(config.calibration_image_format, 'camera', c) );
    I = imresize(I, config.scaling);
    I = im2double( I );
    frameWidth = size(I, 2);
    frameHeight = size(I, 1);
    
    % Load mask
    Imask = im2bw( imread( rok_format_filename(config.mask_format, 'camera', c) ) );
    Imask = imresize(Imask, config.scaling);
    
    %% *** Project grid ***
    % NOTE: we are using the following point annotation
    % A-------B
    % |       |
    % |   E   |
    % |       |
    % D-------C
    
    % Project the bottom grid
    Z = config.height_bottom * ones(size(X));

    bottom.A = rok_camera_project_points( [ X(:)' - room.cell_size(1)/2; Y(:)' - room.cell_size(2)/2; Z(:)' ], calibrationData, config.scaling);
    bottom.B = rok_camera_project_points( [ X(:)' + room.cell_size(1)/2; Y(:)' - room.cell_size(2)/2; Z(:)' ], calibrationData, config.scaling);
    bottom.C = rok_camera_project_points( [ X(:)' + room.cell_size(1)/2; Y(:)' + room.cell_size(2)/2; Z(:)' ], calibrationData, config.scaling);
    bottom.D = rok_camera_project_points( [ X(:)' - room.cell_size(1)/2; Y(:)' + room.cell_size(2)/2; Z(:)' ], calibrationData, config.scaling);
    bottom.E = rok_camera_project_points( [ X(:)';                       Y(:)';                       Z(:)' ], calibrationData, config.scaling);

    % Project the top grid
    Z = config.height_top * ones(size(X));

    top.A = rok_camera_project_points( [ X(:)' - room.cell_size(1)/2; Y(:)' - room.cell_size(2)/2; Z(:)' ], calibrationData, config.scaling);
    top.B = rok_camera_project_points( [ X(:)' + room.cell_size(1)/2; Y(:)' - room.cell_size(2)/2; Z(:)' ], calibrationData, config.scaling);
    top.C = rok_camera_project_points( [ X(:)' + room.cell_size(1)/2; Y(:)' + room.cell_size(2)/2; Z(:)' ], calibrationData, config.scaling);
    top.D = rok_camera_project_points( [ X(:)' - room.cell_size(1)/2; Y(:)' + room.cell_size(2)/2; Z(:)' ], calibrationData, config.scaling);
    top.E = rok_camera_project_points( [ X(:)';                       Y(:)';                       Z(:)' ], calibrationData, config.scaling);
    

    %% *** Compute convex hulls ***
    % Preallocate
    indices = cell(size(top.A, 2), 1);
    vertices = cell(size(top.A, 2), 1);
    area = zeros(size(top.A, 2), 1);
    valid = false(size(top.A, 2), 1);

    % Get the indices for each convex hull
    for i = 1:size(top.A, 2)
        vec = [ top.A(:,i)';
                top.B(:,i)';
                top.C(:,i)';
                top.D(:,i)';
                bottom.A(:,i)';
                bottom.B(:,i)';
                bottom.C(:,i)';
                bottom.D(:,i)';
              ];

        if any(isnan(vec)) 
            continue
        end

        k = convhull(vec);
        hull = vec(k,:);

        % Create mask for pixels inside of polygon (poly2mask is much
        % faster than inpolygon... and gives the same results, except some
        % pixels on the edge. But we can live with that)
        mask = poly2mask(  hull(:,1), hull(:,2), size(Imask, 1), size(Imask, 2) );

        % Store
        indices{i} = uint32( find( mask & Imask ) ); % Both inside and valid; make indices uint32
        vertices{i} = hull;
        area(i) = numel(indices{i});
        valid(i) = ~isempty(indices{i});
    end
    
    if debug,
         % Draw rectangles
        fig = figure;
        imshow(I);
        set(fig, 'Name', 'Convex hulls');
        hold on;

        % Draw the hulls
        for i = 1:numel(vertices),
            if isempty(vertices{i})
                continue;
            end
            
            if valid(i),
                color = 'cyan';
            else
                color = 'red';
            end
                
            line( [ vertices{i}(1:end-1,1),  vertices{i}(2:end,1) ], [ vertices{i}(1:end-1,2),  vertices{i}(2:end,2) ], 'Color', color);
        end
    end
end
    
