classdef testPolytopeView < TestCase
    properties
        Vrep3D
        Hrep3D
        Vrep2D
        Hrep2Dflat
        volume2Dflat
        Hrep3Dunbound
        volume3Dunbound
    end
    
    methods
        function self = testPolytopeView(name)
            self = self@TestCase(name);
        end
        
        function setUp(self)
            self.Vrep3D = obtainVrep('cube');
            self.Hrep3D = obtainHrep('pyramid', 5);
            self.Vrep2D = obtainVrep('square', [], 2);
            
            self.Hrep2Dflat = obtainHrep('line', [], 2);
            self.volume2Dflat = @(flat)(1*flat);
            
            % the following defines the xy-plane
            self.Hrep3Dunbound.A = [-1 0 0; 0 -1 0; 0 0 -1; 0 0 1];
            self.Hrep3Dunbound.h = [0 0 0 0]';
            self.volume3Dunbound = @(flat, infi)(infi*infi*flat);
        end
        
        function tearDown(self)
            
        end
        
        function testHrep3D(self)
            viewPolytope(self.Hrep3D);
            close all
        end
        
        function testVrep2D(self)
            viewPolytope(self.Vrep2D);
            close all
        end
        
        function testGraphOptionsVrep2D(self)
            h = viewPolytope(self.Vrep2D, ...
                'shade', 0.42,...
                'color', [1 0 0],...
                'linestyle', ':',...
                'linewidth', 5,...
                'edgecolor', [0 0 0.23], ...
                'option', struct('color', [0 0.42 0]));
            assertTrue(sum(ishandle(h)) > 0, 'viewPolytope should return a handle');
            assertEqual(length(h), 1, 'number of patches should be 1');
            
            assertEqual(get(h(1), 'LineStyle'), ':', ...
                'style mismatch');
            assertEqual(get(h(1), 'FaceAlpha'), 0.42, ...
                'style mismatch');
            assertEqual(get(h(1), 'FaceColor'), [0 0.42 0], ...
                'style mismatch');
            assertEqual(get(h(1), 'LineWidth'), 5, ...
                'style mismatch');
            assertEqual(get(h(1), 'EdgeColor'), [0 0 0.23], ...
                'style mismatch');
            
            close all
        end
        
        function testNumericOptionsHrep3Dunbound(self)
            h = viewPolytope(self.Hrep3Dunbound, ...
                'option', struct('flatness', 1e-1, ...
                                 'infinityBoxSize', 1e2));

            assertTrue(sum(ishandle(h)) > 0, 'viewPolytope should return a handle');
            assertEqual(length(h), 6, 'number of patches should be 6');
            
            xData = get(h, 'XData');
            yData = get(h, 'YData');
            zData = get(h, 'ZData');
            
            Vrep = zeros(6*4, 3);
            for iFacet = 1:6
                for iVertex = 1:4
                    iVrep = (iFacet - 1)*4 + (iVertex-1) + 1;
                    Vrep(iVrep, 1) = xData{iFacet}(iVertex);
                    Vrep(iVrep, 2) = yData{iFacet}(iVertex);
                    Vrep(iVrep, 3) = zData{iFacet}(iVertex);
                end
            end
            Vrep = unique(Vrep, 'rows');
            [K, V] = convhull(Vrep);
            
            assertElementsAlmostEqual(V, self.volume3Dunbound(1e-1, 1e2), ...
                'absolute', 2e-10, eps, ...
                'computed size mismatch (flatness/infinityBoxSize)');
            
            close all
        end
        
        function testNumericOptionsHrep2Dflat(self)
            h = viewPolytope(self.Hrep2Dflat, ...
                'flatness', 1e-5);

            assertTrue(sum(ishandle(h)) > 0, 'viewPolytope should return a handle');
            assertEqual(length(h), 1, 'number of patches should be 1');
            
            Vrep = [get(h, 'XData'), get(h, 'YData')];

            [K, V] = convhull(Vrep);

            assertElementsAlmostEqual(V, self.volume2Dflat(1e-5), ...
                'relative', eps, eps, ...
                'computed size mismatch (flatness/infinityBoxSize)');
            
            close all
        end
        
        function testPaintFacet(self)
            polytope = obtainHrep('pyramid',5);
            h = viewPolytope(polytope);
            colorMatrix = [1 0 1; 0 1 0; 0 0 1; 1 1 0; 0 1 1; 1 0 0];
            paintFacet(h, polytope.A, colorMatrix);

            for iFacet = 1:length(h)
                thisColor = get(h(iFacet),'FaceColor');
                thisDataX = get(h(iFacet),'Xdata')';
                thisDataY = get(h(iFacet),'Ydata')';
                thisDataZ = get(h(iFacet),'Zdata')';

                thisFilter = abs(bsxfun(@minus, ...
                    polytope.A * [thisDataX; thisDataY; thisDataZ], ...
                    polytope.h)) < 1e-10;
                thisFacetIndex = find(all(thisFilter, 2));
                
                if numel(thisFacetIndex) ~= 1
                    error('elk:polytope:test', 'facet not identified: test does not work');
                end
                
                assertEqual(colorMatrix(thisFacetIndex, :), thisColor, ...
                    'Facet color does not match');
            end
            close all
        end

    end
end

% returns handle?
% valid for all representations?