]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/save/MapGrouter.java
65e23c09fabe3962f41833a6a4c64467a97bda94
[GpsPrune.git] / tim / prune / save / MapGrouter.java
1 package tim.prune.save;
2
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;
9
10 import java.awt.Color;
11 import java.awt.Graphics;
12 import java.awt.Image;
13 import java.awt.image.BufferedImage;
14
15
16 /**
17  * Class to handle the sticking together (grouting) of map tiles
18  * to create a single map image for the current track
19  */
20 public abstract class MapGrouter
21 {
22         /** The most recently produced image */
23         private static GroutedImage _lastGroutedImage = null;
24
25         /**
26          * Clear the last image, it's not needed any more
27          */
28         public static void clearMapImage() {
29                 _lastGroutedImage = null;
30         }
31
32         /**
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
38          */
39         public static GroutedImage createMapImage(Track inTrack, MapSource inMapSource, int inZoom)
40         {
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();
46
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);
55
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);
65
66                 int numTilesUsed = 0;
67                 int numTilesMissing = 0;
68                 // Loop over the tiles
69                 for (int x = minTileX; x <= maxTileX; x++)
70                 {
71                         int yOffset = (int) ((minTileY - yRange.getMinimum() * zoomFactor) * 256);
72                         for (int y = minTileY; y <= maxTileY; y++)
73                         {
74                                 for (int layer=0; layer < inMapSource.getNumLayers(); layer++)
75                                 {
76                                         Image tile = DiskTileCacher.getTile(cachePath, inMapSource.makeFilePath(layer, inZoom, x, y), false);
77                                         if (tile != null)
78                                         {
79                                                 // Wait until tile is available (loaded asynchronously)
80                                                 while (tile.getWidth(null) < 0) {
81                                                         try {
82                                                                 Thread.sleep(100);
83                                                         }
84                                                         catch (InterruptedException ie) {}
85                                                 }
86                                                 // work out where to copy it to, paint it
87                                                 // System.out.println("Painting tile " + x + "," + y + " at " + xOffset + "," + yOffset);
88                                                 numTilesUsed++;
89                                                 g.drawImage(tile, xOffset, yOffset, null);
90                                         }
91                                         else numTilesMissing++;
92                                 }
93                                 yOffset += 256;
94                         }
95                         xOffset += 256;
96                 }
97                 // Get rid of the image if it's empty
98                 if (numTilesUsed == 0) {
99                         resultImage = null;
100                 }
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);
105                 return result;
106         }
107
108         /**
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
114          */
115         public static GroutedImage getMapImage(Track inTrack, MapSource inMapSource, int inZoom)
116         {
117                 if (_lastGroutedImage == null) {
118                         _lastGroutedImage = createMapImage(inTrack, inMapSource, inZoom);
119                 }
120                 return _lastGroutedImage;
121         }
122
123         /**
124          * @param inTrack track object
125          * @param inZoom selected zoom level
126          * @return true if the image size is acceptable
127          */
128         public static boolean isZoomLevelOk(Track inTrack, int inZoom)
129         {
130                 // Get the extents of the track including a standard (10%) border around the data
131                 TrackExtents extents = new TrackExtents(inTrack);
132                 extents.applySquareBorder();
133
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;
138         }
139 }