classdef testPolytopeMeasure < TestCase
    properties
        simpleVrep
        simpleHrep
        simpleVolume
    end
    
    methods
        %% Setup functions
        function self = testPolytopeMeasure(name)
            self = self@TestCase(name);
        end
        
        function setUp(self)
            % simple example: cube
%             self.simpleVrep = obtainVrep('cube');
%             self.simpleHrep = obtainHrep('cube');
%             self.simpleVolume = 1;
            %
            self.simpleVrep = obtainVrep('bipyramid', 4);
            self.simpleHrep = obtainHrep('bipyramid', 4);
            self.simpleVolume = 4/3;
        end
        
        function tearDown(self)
        end
        
        %% obtainMeasureInfo
        % this funtion would be a function in the private folder if it 
        %   would not be required by decomposition, also.
        % This function is considered to be extensively tested by
        %   decompositions.
        function testObtainMeasure(self)
            thisA = self.simpleHrep.A;
            nOne = 5;
            nTwo = size(thisA, 1) - nOne;
            thisG = [ones(nOne, 1), zeros(nOne, 1); ...
                     zeros(nTwo, 1), ones(nTwo, 1)];
                 
            % test with volume
            result = obtainMeasureInfo('volume', thisA);
            assertElementsAlmostEqual(self.simpleVolume, ...
                result.handleHrep(self.simpleHrep), 'relative', eps, eps, ...,
                'obtainMeasureInfo - handleHrep fails');
            assertElementsAlmostEqual(self.simpleVolume, ...
                result.handleVrep(self.simpleVrep), 'relative', eps, eps, ...,
                'obtainMeasureInfo - handleHrep fails');
            assertElementsAlmostEqual(self.simpleVolume, ...
                result.handleH(self.simpleHrep.h), 'relative', eps, eps, ...,
                'obtainMeasureInfo - handleH fails');
            assertEqual(result.dim, 3, 'dimension mismatch');
            assertEqual(result.name, 'volume', 'name mismatch');
            assertEqual(result.isPar, 0, 'isPar mismatch');
        end
        
        %% test volume
        function testVolumeVrep(self)
            volume = computeVolumeVrep(self.simpleVrep);
            assertElementsAlmostEqual(volume, self.simpleVolume, 'relative', eps, eps, ...
                'Volume computation failed.');
        end
        
        function testVolumeHrep(self)
            volume = computeVolumeHrep(self.simpleHrep);
            assertElementsAlmostEqual(volume, self.simpleVolume, 'relative', eps, eps, ...
                'Volume computation failed.');
        end
        
        function testVolumeSmall(self)
            scaleFactor = 1e-20;
            vrep.V = self.simpleVrep.V * scaleFactor;
            volume = computeVolumeVrep(vrep);
            assertElementsAlmostEqual(log(volume), log(self.simpleVolume*scaleFactor^3), 'relative', eps, eps, ...
                'Volume computation failed.');
        end
    
        function testVolumeLarge(self)
            scaleFactor = 1e20;
            vrep.V = self.simpleVrep.V * scaleFactor;
            volume = computeVolumeVrep(vrep);
            assertElementsAlmostEqual(volume, self.simpleVolume*scaleFactor^3, ...
                'relative', eps, eps, ...
                'Volume computation failed.');
        end
        
        %% test facet/surface area
        function testSurfaceVrep(self)
            vrep = obtainVrep('cube');
            area = computeFacetAreaVrep(vrep);
            assertElementsAlmostEqual(area, 6, 'relative', eps, eps, ...
                'Surface area computation failed.');
        end
        
        function testSurfaceHrep(self)
            hrep = obtainHrep('cube');
            area = computeFacetAreaHrep(hrep);
            assertElementsAlmostEqual(area, 6, 'relative', eps, eps, ...
                'Surface area computation failed.');
        end
        
        function testFacetAreaVrep(self)
            vrep = obtainVrep('cube');
            dirMatrix = [1 0 0;0 -1 0; 1 1 0; 1 1 1];
            areaResult = [1 1 0 0];
            area = computeFacetAreaVrep(vrep, dirMatrix);
            assertElementsAlmostEqual(area, areaResult, 'relative', eps, eps, ...
                'Facet area computation failed.');
        end
        
        function testFacetAreaHrep(self)
            hrep = obtainHrep('cube');
            dirMatrix = [1 0 0;0 -1 0; 1 1 0; 1 1 1];
            areaResult = [1 1 0 0];
            area = computeFacetAreaHrep(hrep, dirMatrix);
            assertElementsAlmostEqual(area, areaResult, 'relative', eps, eps, ...
                'Facet area computation failed.');
        end
        
        %% projection
        function testProjectionVrep(self)
            vrep = obtainVrep('cube');
            dirMatrix = [1 0 0; 0 -1  0;...
                         1 1 0; 0  1 -1];
            areaResult = [1 1 sqrt(2) sqrt(2)];
            area = computeProjectionAreaVrep(vrep, dirMatrix);
            assertElementsAlmostEqual(area, areaResult, 'relative', eps, eps, ...
                'Projection area computation failed.');
        end
        
        function testProjectionHrep(self)
            hrep = obtainHrep('cube');
            dirMatrix = [1 0 0; 0 -1  0;...
                         1 1 0; 0  1 -1];
            areaResult = [1 1 sqrt(2) sqrt(2)];
            area = computeProjectionAreaHrep(hrep, dirMatrix);
            assertElementsAlmostEqual(area, areaResult, 'relative', eps, eps, ...
                'Projection area computation failed.');
        end
        
        function testProjectionFlatVrep(self)
            vrep = obtainVrep('square');
            dirMatrix = [0 0 1; 1 1 0; 1 0 0];
            areaResult = [1 0 0];
            area = computeProjectionAreaVrep(vrep, dirMatrix);
            assertElementsAlmostEqual(area, areaResult, 'relative', eps, eps, ...
                'Projection area computation failed.');
        end
        
        %% Feret
        function testFeretVrep(self)
            vrep = obtainVrep('cube');
            dirMatrix = [1 0 0; 0 -3  0;...
                         1 1 0; 0  4 -4;...
                         1 1 1; 2 2 2];
            diameterResult = [1 1 sqrt(2) sqrt(2) sqrt(3) sqrt(3)];
            diameter = computeFeretVrep(vrep, dirMatrix);
            assertElementsAlmostEqual(diameter, diameterResult, 'relative', eps, eps, ...
                'Feret diameter computation failed.');
        end    
        
        function testFeretHrep(self)
            hrep = obtainHrep('cube');
            dirMatrix = [1 0 0; 0 -3  0;...
                         1 1 0; 0  4 -4;...
                         1 1 1; 2 2 2];
            diameterResult = [1 1 sqrt(2) sqrt(2) sqrt(3) sqrt(3)];
            diameter = computeFeretHrep(hrep, dirMatrix);
            assertElementsAlmostEqual(diameter, diameterResult, 'relative', eps, eps, ...
                'Feret diameter computation failed.');
        end   
        
        %% Mean width
        % [Finch, 2011 (unpublished): "Mean Width of a Regular Simplex"] gives the
        % mean width of the unit cube with: 1.5
        function testMeanWidthHrep(self)
            hrep = obtainHrep('cube');
            widthResult = 1.5;
            width = computeMeanWidthHrep(hrep);
            assertElementsAlmostEqual(width, widthResult, 'relative', eps, eps, ...
                'Mean width computation failed.');
        end
        
        function testMeanWidth2D(self)
           vrep = obtainVrep('square',[],2);
           widthResult = 4/pi;
           width = computeMeanWidthVrep(vrep);
           assertElementsAlmostEqual(width, widthResult, 'relative', eps, eps, ...
               '2D mean width computation failed');
        end
        
        %% computeEdgeSet
        % is contained in computeMeanWidth.. ..not yet extensively testet.
        
        %% edge length
        function testEdgeLength(self)
            % for vrep
            thisVrep = self.simpleVrep;
            dirMatrix = [1 1 0; 1 0 0; 0 1 1];
            edgeLengthVector = computeEdgeLengthVrep(thisVrep, dirMatrix);
            assertElementsAlmostEqual(edgeLengthVector, ...
                [sqrt(2) 0 sqrt(2)], 'relative', eps, 10*eps, ...
                'Edge length for vrep does not match');
            % for hrep
            thisHrep = self.simpleHrep;
            edgeLengthVector = computeEdgeLengthHrep(thisHrep, dirMatrix, 1e-10);
            assertElementsAlmostEqual(edgeLengthVector, ...
                [sqrt(2) 0 sqrt(2)], 'relative', eps, 10*eps, ...
                'Edge length for hrep does not match');
        end
        
        
        %% 1D-measures
        function testMeasures1d(self)
            vrep = obtainVrep('line', [], 1);
            vrep = stretchVrep(vrep, 3);
            vrep = moveVrep(vrep, -1);
            %% volume
            volume = computeVolumeVrep(vrep);
            assertElementsAlmostEqual(volume, 3,'relative', eps, eps, ...
                '1D volume computation failed');
            %% support
            support = computeSupportValueVrep(vrep,[1; -1]);
            assertElementsAlmostEqual(support, [2 1]', 'relative', eps, eps, ...
                '1D support value computation failed');
            %% projection area
            proj_area = computeProjectionAreaVrep(vrep,[0 0 1]);
            assertElementsAlmostEqual(proj_area, 0, 'relative', eps, eps, ...
                '1D projection area computation failed');
            %% mean width
            mean_width = computeMeanWidthVrep(vrep);
            assertElementsAlmostEqual(mean_width, 3, 'relative', eps, eps, ...
                '1D mean width computation failed');
            %% facet area
            facet_area = computeFacetAreaVrep(vrep);
            assertElementsAlmostEqual(facet_area, 0, 'relative', eps, eps, ...
                '1D facet area computation failed');
            %% edge length
            edge_length = computeEdgeLengthVrep(vrep,1);
            assertElementsAlmostEqual(edge_length, 0, 'relative', eps, eps, ...
                '1D edge length computation failed');
            %% feret
            feret = computeFeretVrep(vrep,1);assertElementsAlmostEqual(feret, 3, 'relative', eps, eps, ...
                '1D feret diameter computation failed');
        end
    end
end