/*
* Copyright (C) 2015 Patryk Strach
*
* This file is part of Virtual Slide Viewer.
*
* Virtual Slide Viewer is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* Virtual Slide Viewer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Virtual Slide Viewer.
* If not, see <http://www.gnu.org/licenses/>.
*/
package virtualslideviewer.ui.imageviewing;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import virtualslideviewer.testutils.TestUtil;
import virtualslideviewer.ui.imageviewing.Camera;
public class CameraTest
{
private List<Dimension> mImageResolutions = new ArrayList<>();
private Camera mTestedCamera;
@Before
public void setUp() throws Exception
{
mTestedCamera = new Camera();
mTestedCamera.setImageSize(new Dimension(16000, 8000));
mImageResolutions.add(new Dimension( 1000, 500));
mImageResolutions.add(new Dimension( 2000, 1000));
mImageResolutions.add(new Dimension( 4000, 2000));
mImageResolutions.add(new Dimension( 8000, 4000));
mImageResolutions.add(new Dimension(16000, 8000));
}
@Test
public void testGettingVisibleRegionBoundsWithValidValuesAndWithoutZoom()
{
mTestedCamera.setZoom(1.0);
mTestedCamera.setPosition(new Point2D.Double(0.625, 0.5));
mTestedCamera.setViewportSize(new Dimension(160, 400));
assertThat(mTestedCamera.getVisibleRegionBounds(), TestUtil.is(new Rectangle2D.Double(0.62, 0.475, 0.01, 0.05)));
assertThat(mTestedCamera.getAbsoluteVisibleRegionBounds(), is(new Rectangle(9920, 3800, 160, 400)));
}
@Test
public void testGettingVisibleRegionBoundsWithValidValuesAndWithZoom()
{
mTestedCamera.setZoom(0.25);
mTestedCamera.setPosition(new Point2D.Double(0.625, 0.5));
mTestedCamera.setViewportSize(new Dimension(160, 400));
assertThat(mTestedCamera.getVisibleRegionBounds(), TestUtil.is(new Rectangle2D.Double(0.605, 0.4, 0.04, 0.2)));
assertThat(mTestedCamera.getAbsoluteVisibleRegionBounds(), is(new Rectangle(2420, 800, 160, 400)));
}
@Test
public void testInvalidRegionCenterIsCorrected()
{
mTestedCamera.setZoom(0.5);
mTestedCamera.setPosition(new Point2D.Double(0.5, 0.9));
mTestedCamera.setViewportSize(new Dimension(1000, 2000));
assertThat(mTestedCamera.getVisibleRegionBounds(), TestUtil.is(new Rectangle2D.Double(0.4375, 0.5, 0.125, 0.5)));
assertThat(mTestedCamera.getAbsoluteVisibleRegionBounds(), is(new Rectangle(3500, 2000, 1000, 2000)));
}
@Test
public void testPanningWithValidTranslation()
{
mTestedCamera.setZoom(0.5);
mTestedCamera.setPosition(new Point2D.Double(0.5, 0.75));
mTestedCamera.setViewportSize(new Dimension(160, 100));
mTestedCamera.pan(new Point(1000, -500));
assertThat(mTestedCamera.getVisibleRegionBounds(), TestUtil.is(new Rectangle2D.Double(0.615, 0.6125, 0.02, 0.025)));
assertThat(mTestedCamera.getAbsoluteVisibleRegionBounds(), is(new Rectangle(4920, 2450, 160, 100)));
}
@Test
public void testPanningClipsResultingPositionToImageBounds()
{
mTestedCamera.setZoom(0.75);
mTestedCamera.setPosition(new Point2D.Double(0.25, 0.8));
mTestedCamera.setViewportSize(new Dimension(600, 360));
mTestedCamera.pan(new Point(-900, 3000));
assertThat(mTestedCamera.getVisibleRegionBounds(), TestUtil.is(new Rectangle2D.Double(0.15, 0.94, 0.05, 0.06)));
assertThat(mTestedCamera.getAbsoluteVisibleRegionBounds(), is(new Rectangle(1800, 5640, 600, 360)));
}
@Test
public void testPanningStartsFromImageEdgeWhenCenterHasBeenSetToOutsideOfImageBounds()
{
mTestedCamera.setZoom(0.25);
mTestedCamera.setPosition(new Point2D.Double(2.0, 0.5));
mTestedCamera.setViewportSize(new Dimension(600, 360));
mTestedCamera.pan(new Point(-500, 180));
assertThat(mTestedCamera.getVisibleRegionBounds(), TestUtil.is(new Rectangle2D.Double(0.725, 0.5, 0.15, 0.18)));
assertThat(mTestedCamera.getAbsoluteVisibleRegionBounds(), is(new Rectangle(2900, 1000, 600, 360)));
}
@Test
public void testZoomingAtCenterCorrectlyUpdatesVisibleRegionBounds()
{
mTestedCamera.setZoom(1.0);
mTestedCamera.setPosition(new Point2D.Double(0.4, 0.25));
mTestedCamera.setViewportSize(new Dimension(320, 800));
mTestedCamera.setZoom(0.5);
assertThat(mTestedCamera.getVisibleRegionBounds(), TestUtil.is(new Rectangle2D.Double(0.38, 0.15, 0.04, 0.2)));
assertThat(mTestedCamera.getAbsoluteVisibleRegionBounds(), is(new Rectangle(3040, 600, 320, 800)));
}
@Test
public void testZoomingAtArbitraryPointCorrectlyUpdatesVisibleRegionBounds()
{
mTestedCamera.setZoom(0.25);
mTestedCamera.setPosition(new Point2D.Double(0.4, 0.25));
mTestedCamera.setViewportSize(new Dimension(320, 800));
mTestedCamera.setZoom(0.5, new Point(50, 25));
assertThat(mTestedCamera.getVisibleRegionBounds(), TestUtil.is(new Rectangle2D.Double(0.36625, 0.05625, 0.04, 0.2)));
assertThat(mTestedCamera.getAbsoluteVisibleRegionBounds(), is(new Rectangle(2930, 225, 320, 800)));
}
@Test
public void testZoomingAtArbitraryPointCorrectlyUpdatesVisibleRegionBoundsWhenRegionCenterIsOutOfImageBounds()
{
mTestedCamera.setZoom(1.0);
mTestedCamera.setPosition(new Point2D.Double(0.4, -0.5));
mTestedCamera.setViewportSize(new Dimension(320, 800));
mTestedCamera.setZoom(2.0, new Point(50, 25));
assertThat(mTestedCamera.getVisibleRegionBounds(), TestUtil.is(new Rectangle2D.Double(0.3915625, 0.0015625, 0.01, 0.05)));
assertThat(mTestedCamera.getAbsoluteVisibleRegionBounds(), is(new Rectangle(12530, 25, 320, 800)));
}
@Test
public void testZoomToFitWhenImageIsLargerThanViewport()
{
mTestedCamera.setViewportSize(new Dimension(500, 1000));
mTestedCamera.setImageSize(new Dimension(2000, 3000));
mTestedCamera.zoomToFit();
assertThat(mTestedCamera.getZoom(), is(0.25));
}
@Test
public void testZoomToFitWhenImageIsSmallerThanViewportDoesNotUpscaleIt()
{
mTestedCamera.setViewportSize(new Dimension(800, 1000));
mTestedCamera.setImageSize(new Dimension(500, 600));
mTestedCamera.zoomToFit();
assertThat(mTestedCamera.getZoom(), is(1.0));
}
@Test
public void testRelativeToAbsoluteBoundsConversion()
{
Rectangle2D relativeBounds = new Rectangle2D.Double(0.25, 0.4, 0.125, 0.6);
Dimension areaSize = new Dimension(1000, 2000);
Rectangle returnedBounds = Camera.relativeToAbsoluteBounds(relativeBounds, areaSize);
assertThat(returnedBounds, is(new Rectangle(250, 800, 125, 1200)));
}
@Test
public void testGetBestResolutionReturnsTheLowestResolutionAtLowZoomLevel()
{
mTestedCamera.setZoom(0.003);
int returnedResIndex = mTestedCamera.getBestResolutionForCurrentZoom(mImageResolutions, 0.25);
assertThat(returnedResIndex, is(0));
}
@Test
public void testGetBestResolutionReturnsTheHighestResolutionAtZoomAbove100Percent()
{
mTestedCamera.setZoom(123.32);
int returnedResIndex = mTestedCamera.getBestResolutionForCurrentZoom(mImageResolutions, 0.25);
assertThat(returnedResIndex, is(mImageResolutions.size() - 1));
}
@Test
public void testGetBestResolutionReturnsCorrectResolutionLevelAccordingToGivenThreshold()
{
mTestedCamera.setZoom(0.45);
int returnedResIndexWithHigherThreshold = mTestedCamera.getBestResolutionForCurrentZoom(mImageResolutions, 0.9);
int returnedResIndexWithLowerThreshold = mTestedCamera.getBestResolutionForCurrentZoom(mImageResolutions, 0.7);
assertThat(returnedResIndexWithHigherThreshold, is(2));
assertThat(returnedResIndexWithLowerThreshold, is(3));
}
@Test
public void testListenerIsCalledWhenCameraPositionChanges()
{
Camera.Listener listenerMock = Mockito.mock(Camera.Listener.class);
mTestedCamera.addChangeListener(listenerMock);
mTestedCamera.setPosition(new Point2D.Double(0.35, 0.24));
Mockito.verify(listenerMock).onVisibleRegionUpdate();
}
@Test
public void testListenerIsCalledWhenViewportSizeChanges()
{
Camera.Listener listenerMock = Mockito.mock(Camera.Listener.class);
mTestedCamera.addChangeListener(listenerMock);
mTestedCamera.setViewportSize(new Dimension(100, 200));
Mockito.verify(listenerMock).onVisibleRegionUpdate();
}
@Test
public void testListenerIsCalledWhenCameraIsTranslated()
{
Camera.Listener listenerMock = Mockito.mock(Camera.Listener.class);
mTestedCamera.addChangeListener(listenerMock);
mTestedCamera.pan(new Point(100, 200));
Mockito.verify(listenerMock).onVisibleRegionUpdate();
}
@Test
public void testListenerIsCalledWhenCameraZoomChanges()
{
Camera.Listener listenerMock = Mockito.mock(Camera.Listener.class);
mTestedCamera.addChangeListener(listenerMock);
mTestedCamera.setZoom(0.2);
Mockito.verify(listenerMock).onVisibleRegionUpdate();
}
@Test
public void testListenerIsCalledWhenCameraZoomChangesWhenZoomingAtSpecifingPoint()
{
Camera.Listener listenerMock = Mockito.mock(Camera.Listener.class);
mTestedCamera.addChangeListener(listenerMock);
mTestedCamera.setZoom(0.2, new Point(50, 100));
Mockito.verify(listenerMock).onVisibleRegionUpdate();
}
@Test
public void testListenerIsCalledWhenCameraZoomsToFitEntireImage()
{
Camera.Listener listenerMock = Mockito.mock(Camera.Listener.class);
mTestedCamera.setViewportSize(new Dimension(500, 1000));
mTestedCamera.addChangeListener(listenerMock);
mTestedCamera.zoomToFit();
Mockito.verify(listenerMock).onVisibleRegionUpdate();
}
@Test
public void testListenerIsCalledWhenImageSizeIsChanged()
{
Camera.Listener listenerMock = Mockito.mock(Camera.Listener.class);
mTestedCamera.addChangeListener(listenerMock);
mTestedCamera.setImageSize(new Dimension(1234, 5678));
Mockito.verify(listenerMock).onVisibleRegionUpdate();
}
}