X-Git-Url: http://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fsave%2FMapGrouter.java;fp=tim%2Fprune%2Fsave%2FMapGrouter.java;h=65e23c09fabe3962f41833a6a4c64467a97bda94;hb=7f5ed2be62905bd37717376dc22d09e5ea7edb4d;hp=0000000000000000000000000000000000000000;hpb=b361869e590bbca32664c16ac24d6296926594a5;p=GpsPrune.git diff --git a/tim/prune/save/MapGrouter.java b/tim/prune/save/MapGrouter.java new file mode 100644 index 0000000..65e23c0 --- /dev/null +++ b/tim/prune/save/MapGrouter.java @@ -0,0 +1,139 @@ +package tim.prune.save; + +import tim.prune.config.Config; +import tim.prune.data.DoubleRange; +import tim.prune.data.Track; +import tim.prune.data.TrackExtents; +import tim.prune.gui.map.DiskTileCacher; +import tim.prune.gui.map.MapSource; + +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 abstract class MapGrouter +{ + /** The most recently produced image */ + private static GroutedImage _lastGroutedImage = null; + + /** + * Clear the last image, it's not needed any more + */ + public static 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 static GroutedImage createMapImage(Track inTrack, MapSource inMapSource, int inZoom) + { + // 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(); + + // Get path to disk cache + final String cachePath = Config.getConfigString(Config.KEY_DISK_CACHE); + // 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) {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); + + 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 = DiskTileCacher.getTile(cachePath, inMapSource.makeFilePath(layer, inZoom, x, y), false); + if (tile != null) + { + // Wait until tile is available (loaded asynchronously) + while (tile.getWidth(null) < 0) { + try { + Thread.sleep(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 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 static 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; + } +}