+++ /dev/null
-package tim.prune.save;
-
-import tim.prune.data.DoubleRange;
-import tim.prune.data.Track;
-import tim.prune.data.TrackExtents;
-import tim.prune.gui.map.MapSource;
-import tim.prune.gui.map.MapTileManager;
-import tim.prune.gui.map.TileConsumer;
-
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.Image;
-import java.awt.image.BufferedImage;
-
-
-/**
- * Class to handle the sticking together (grouting) of map tiles
- * to create a single map image for the current track
- */
-public class MapGrouter implements TileConsumer
-{
- /** The most recently produced image */
- private GroutedImage _lastGroutedImage = null;
-
- /**
- * Clear the last image, it's not needed any more
- */
- public void clearMapImage() {
- _lastGroutedImage = null;
- }
-
- /**
- * Grout the required map tiles together according to the track's extent
- * @param inTrack track object
- * @param inMapSource map source to use (may have one or two layers)
- * @param inZoom selected zoom level
- * @return grouted image, or null if no image could be created
- */
- public GroutedImage createMapImage(Track inTrack, MapSource inMapSource, int inZoom)
- {
- return createMapImage(inTrack, inMapSource, inZoom, false);
- }
-
- /**
- * Grout the required map tiles together according to the track's extent
- * @param inTrack track object
- * @param inMapSource map source to use (may have one or two layers)
- * @param inZoom selected zoom level
- * @param inDownload true to download tiles, false (by default) to just pull from disk
- * @return grouted image, or null if no image could be created
- */
- public GroutedImage createMapImage(Track inTrack, MapSource inMapSource, int inZoom, boolean inDownload)
- {
- // Get the extents of the track including a standard (10%) border around the data
- TrackExtents extents = new TrackExtents(inTrack);
- extents.applySquareBorder();
- DoubleRange xRange = extents.getXRange();
- DoubleRange yRange = extents.getYRange();
-
- // Work out which tiles are required
- final int zoomFactor = 1 << inZoom;
- final int minTileX = (int) (xRange.getMinimum() * zoomFactor);
- final int maxTileX = (int) (xRange.getMaximum() * zoomFactor);
- final int minTileY = (int) (yRange.getMinimum() * zoomFactor);
- final int maxTileY = (int) (yRange.getMaximum() * zoomFactor);
-
- // Work out how big the final image will be, create a BufferedImage
- final int pixCount = (int) (extents.getXRange().getRange() * zoomFactor * 256);
- if (pixCount < 2 || inZoom == 0) {return null;}
- BufferedImage resultImage = new BufferedImage(pixCount, pixCount, BufferedImage.TYPE_INT_RGB);
- Graphics g = resultImage.getGraphics();
- g.setColor(Color.WHITE);
- g.fillRect(0, 0, pixCount, pixCount);
- // Work out where to start drawing the tiles on the image
- int xOffset = (int) ((minTileX - xRange.getMinimum() * zoomFactor) * 256);
-
- // Make a map tile manager to load (or download) the tiles
- MapTileManager tileManager = new MapTileManager(this);
- tileManager.setMapSource(inMapSource);
- tileManager.enableTileDownloading(inDownload);
- tileManager.setReturnIncompleteImages();
- tileManager.setZoom(inZoom);
-
- int numTilesUsed = 0;
- int numTilesMissing = 0;
-
- // Loop over the tiles
- for (int x = minTileX; x <= maxTileX; x++)
- {
- int yOffset = (int) ((minTileY - yRange.getMinimum() * zoomFactor) * 256);
- for (int y = minTileY; y <= maxTileY; y++)
- {
- for (int layer=0; layer < inMapSource.getNumLayers(); layer++)
- {
- Image tile = tileManager.getTile(layer, x, y, true);
- // If we're downloading tiles, wait until the tile isn't null
- int waitCount = 0;
- while (tile == null && inDownload && waitCount < 3)
- {
- // System.out.println("wait " + waitCount + " for tile to be not null");
- try {Thread.sleep(250);} catch (InterruptedException e) {}
- tile = tileManager.getTile(layer, x, y, false); // don't request another download
- waitCount++;
- }
- // See if there's a tile or not
- if (tile != null)
- {
- // Wait until tile is available (loaded asynchronously)
- while (tile.getWidth(null) < 0 && !inDownload)
- {
- // System.out.println("Wait for tile width");
- try {
- Thread.sleep(inDownload ? 500 : 100);
- }
- catch (InterruptedException ie) {}
- }
- // work out where to copy it to, paint it
- // System.out.println("Painting tile " + x + "," + y + " at " + xOffset + "," + yOffset);
- numTilesUsed++;
- g.drawImage(tile, xOffset, yOffset, null);
- }
- else
- {
- // null tile, that means it's either not available or really slow to start downloading
- numTilesMissing++;
- }
- }
- yOffset += 256;
- }
- xOffset += 256;
- }
- // Get rid of the image if it's empty
- if (numTilesUsed == 0) {
- resultImage = null;
- }
- // Store the xy limits in the GroutedImage to make it easier to draw on top
- GroutedImage result = new GroutedImage(resultImage, numTilesUsed, numTilesMissing);
- result.setXRange(xRange);
- result.setYRange(yRange);
- return result;
- }
-
- /**
- * Get the grouted map image, using the previously-created one if available
- * @param inTrack track object
- * @param inMapSource map source to use (may have one or two layers)
- * @param inZoom selected zoom level
- * @return grouted image, or null if no image could be created
- */
- public synchronized GroutedImage getMapImage(Track inTrack, MapSource inMapSource, int inZoom)
- {
- if (_lastGroutedImage == null) {
- _lastGroutedImage = createMapImage(inTrack, inMapSource, inZoom);
- }
- return _lastGroutedImage;
- }
-
- /**
- * @param inTrack track object
- * @param inZoom selected zoom level
- * @return true if the image size is acceptable
- */
- public static boolean isZoomLevelOk(Track inTrack, int inZoom)
- {
- // Get the extents of the track including a standard (10%) border around the data
- TrackExtents extents = new TrackExtents(inTrack);
- extents.applySquareBorder();
-
- // Work out how big the final image will be
- final int zoomFactor = 1 << inZoom;
- final int pixCount = (int) (extents.getXRange().getRange() * zoomFactor * 256);
- return pixCount > 2 && pixCount < 4000;
- }
-
- /** React to tiles being updated by the tile manager */
- public void tilesUpdated(boolean inIsOk)
- {
- // Doesn't need any action
- }
-}