1 package tim.prune.save;
3 import tim.prune.config.Config;
4 import tim.prune.data.DoubleRange;
5 import tim.prune.data.Track;
6 import tim.prune.data.TrackExtents;
7 import tim.prune.gui.map.DiskTileCacher;
8 import tim.prune.gui.map.MapSource;
10 import java.awt.Color;
11 import java.awt.Graphics;
12 import java.awt.Image;
13 import java.awt.image.BufferedImage;
17 * Class to handle the sticking together (grouting) of map tiles
18 * to create a single map image for the current track
20 public abstract class MapGrouter
22 /** The most recently produced image */
23 private static GroutedImage _lastGroutedImage = null;
26 * Clear the last image, it's not needed any more
28 public static void clearMapImage() {
29 _lastGroutedImage = null;
33 * Grout the required map tiles together according to the track's extent
34 * @param inTrack track object
35 * @param inMapSource map source to use (may have one or two layers)
36 * @param inZoom selected zoom level
37 * @return grouted image, or null if no image could be created
39 public static GroutedImage createMapImage(Track inTrack, MapSource inMapSource, int inZoom)
41 // Get the extents of the track including a standard (10%) border around the data
42 TrackExtents extents = new TrackExtents(inTrack);
43 extents.applySquareBorder();
44 DoubleRange xRange = extents.getXRange();
45 DoubleRange yRange = extents.getYRange();
47 // Get path to disk cache
48 final String cachePath = Config.getConfigString(Config.KEY_DISK_CACHE);
49 // Work out which tiles are required
50 final int zoomFactor = 1 << inZoom;
51 final int minTileX = (int) (xRange.getMinimum() * zoomFactor);
52 final int maxTileX = (int) (xRange.getMaximum() * zoomFactor);
53 final int minTileY = (int) (yRange.getMinimum() * zoomFactor);
54 final int maxTileY = (int) (yRange.getMaximum() * zoomFactor);
56 // Work out how big the final image will be, create a BufferedImage
57 final int pixCount = (int) (extents.getXRange().getRange() * zoomFactor * 256);
58 if (pixCount < 2) {return null;}
59 BufferedImage resultImage = new BufferedImage(pixCount, pixCount, BufferedImage.TYPE_INT_RGB);
60 Graphics g = resultImage.getGraphics();
61 g.setColor(Color.WHITE);
62 g.fillRect(0, 0, pixCount, pixCount);
63 // Work out where to start drawing the tiles on the image
64 int xOffset = (int) ((minTileX - xRange.getMinimum() * zoomFactor) * 256);
67 int numTilesMissing = 0;
68 // Loop over the tiles
69 for (int x = minTileX; x <= maxTileX; x++)
71 int yOffset = (int) ((minTileY - yRange.getMinimum() * zoomFactor) * 256);
72 for (int y = minTileY; y <= maxTileY; y++)
74 for (int layer=0; layer < inMapSource.getNumLayers(); layer++)
76 Image tile = DiskTileCacher.getTile(cachePath, inMapSource.makeFilePath(layer, inZoom, x, y), false);
79 // Wait until tile is available (loaded asynchronously)
80 while (tile.getWidth(null) < 0) {
84 catch (InterruptedException ie) {}
86 // work out where to copy it to, paint it
87 // System.out.println("Painting tile " + x + "," + y + " at " + xOffset + "," + yOffset);
89 g.drawImage(tile, xOffset, yOffset, null);
91 else numTilesMissing++;
97 // Get rid of the image if it's empty
98 if (numTilesUsed == 0) {
101 // Store the xy limits in the GroutedImage to make it easier to draw on top
102 GroutedImage result = new GroutedImage(resultImage, numTilesUsed, numTilesMissing);
103 result.setXRange(xRange);
104 result.setYRange(yRange);
109 * Get the grouted map image, using the previously-created one if available
110 * @param inTrack track object
111 * @param inMapSource map source to use (may have one or two layers)
112 * @param inZoom selected zoom level
113 * @return grouted image, or null if no image could be created
115 public static GroutedImage getMapImage(Track inTrack, MapSource inMapSource, int inZoom)
117 if (_lastGroutedImage == null) {
118 _lastGroutedImage = createMapImage(inTrack, inMapSource, inZoom);
120 return _lastGroutedImage;
124 * @param inTrack track object
125 * @param inZoom selected zoom level
126 * @return true if the image size is acceptable
128 public static boolean isZoomLevelOk(Track inTrack, int inZoom)
130 // Get the extents of the track including a standard (10%) border around the data
131 TrackExtents extents = new TrackExtents(inTrack);
132 extents.applySquareBorder();
134 // Work out how big the final image will be
135 final int zoomFactor = 1 << inZoom;
136 final int pixCount = (int) (extents.getXRange().getRange() * zoomFactor * 256);
137 return pixCount > 2 && pixCount < 4000;