/*
* 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.imageviewing;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import virtualslideviewer.core.BufferedVirtualSlideImage;
import virtualslideviewer.core.ImageIndex;
import virtualslideviewer.core.Tile;
/**
* A prefetching strategy which prefetches neighbouring tiles in specified radius.
*/
public class NeighbourPrefetchingStrategy implements PrefetchingStrategy
{
private final int mPrefetchingRadius;
/**
* @param prefetchingRadius The radius in pixels of area to prefetch.
*/
public NeighbourPrefetchingStrategy(int prefetchingRadius)
{
mPrefetchingRadius = prefetchingRadius;
}
@Override
public List<Tile> getTilesToPrefetch(BufferedVirtualSlideImage image, Rectangle loadedImagePart, ImageIndex imageIndex)
{
Rectangle loadedTiles = getLoadedTilesBounds(loadedImagePart, image.getTileSize(imageIndex.getResolutionIndex()));
Rectangle prefetchingRegion = getPrefetchingRegion(loadedTiles, image, imageIndex.getResolutionIndex());
List<Tile> tilesToPrefetch = new ArrayList<Tile>();
for(int y = prefetchingRegion.y; y < prefetchingRegion.getMaxY(); y++)
{
for(int x = prefetchingRegion.x; x < prefetchingRegion.getMaxX(); x++)
{
if(!loadedTiles.contains(x, y))
{
tilesToPrefetch.add(new Tile(x, y, imageIndex));
}
}
}
return tilesToPrefetch;
}
private Rectangle getLoadedTilesBounds(Rectangle loadedImagePart, Dimension tileSize)
{
int x1 = (int)Math.floor(loadedImagePart.getX() / tileSize.getWidth());
int y1 = (int)Math.floor(loadedImagePart.getY() / tileSize.getHeight());
int x2 = (int)Math.ceil((loadedImagePart.getMaxX()) / tileSize.getWidth());
int y2 = (int)Math.ceil((loadedImagePart.getMaxY()) / tileSize.getHeight());
return new Rectangle(x1, y1, x2 - x1, y2 - y1);
}
private Rectangle getPrefetchingRegion(Rectangle loadedTilesBounds, BufferedVirtualSlideImage image, int resIndex)
{
Dimension tileSize = image.getTileSize(resIndex);
Dimension tilePrefetchingRadius = getPrefetchingRadiusInTiles(tileSize);
int tileColumns = (int)Math.ceil(image.getImageSize(resIndex).getWidth() / tileSize.getWidth());
int tileRows = (int)Math.ceil(image.getImageSize(resIndex).getHeight() / tileSize.getHeight());
int x1 = (int)Math.max(loadedTilesBounds.getX() - tilePrefetchingRadius.getWidth(), 0);
int y1 = (int)Math.max(loadedTilesBounds.getY() - tilePrefetchingRadius.getHeight(), 0);
int x2 = (int)Math.min(loadedTilesBounds.getMaxX() + tilePrefetchingRadius.getWidth(), tileColumns);
int y2 = (int)Math.min(loadedTilesBounds.getMaxY() + tilePrefetchingRadius.getHeight(), tileRows);
return new Rectangle(x1, y1, x2 - x1, y2 - y1);
}
private Dimension getPrefetchingRadiusInTiles(Dimension tileSize)
{
int tilesInX = (int)Math.ceil(mPrefetchingRadius / tileSize.getWidth());
int tilesInY = (int)Math.ceil(mPrefetchingRadius / tileSize.getHeight());
return new Dimension(tilesInX, tilesInY);
}
}