I had a set of map tiles generated using Microsoft Research’s free and pretty useful MapCruncher tool. The problem is that it outputs the tiles in the “Quadtree” format used by Bing maps (fair enough) so that you can easily create a Bing maps mashup, whereas I wanted to use the resultant tiles with one of the many popular javascript mapping libraries out there, in this particular case Leaflet.js.
Most of these libraries come with plugins so that you can use different sources for the map tiles, but for Layer I couldn’t find one that would allow me to easily use the MapCruncher Quadtree tiles directly.
As fortune would have it, the actual files that quadtree uses are the same tiles that are used in the more widely-standardised ZXY format. The only difference is in the naming of the files and the way they are all stored in a single directory for Quadtree vs being in subfolders for ZXY (where the Z is the zoom level).
Therefore, using a known formula you can rename and move the quadtree files to get a set of files that can be used directly by most map-rendering javascripts using the default map provider.
The raw Java code I used for this is below. When I get time I’ll try and package this into a jar file or put a basic GUI on it for you, but in the meantime, you’ll have to compile and run it yourself, sorry.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; public class QuadtreeToTMS { /** * @param args */ public static void main(String[] args) { //go into source directory of quadtree tiles final File inputDir = new File(“C:\\tiles\\crunchertiles\\Layer_NewLayer”); final String outputDir = “C:\\tiles\\zxy”; //for each tile for (final File inFile : inputDir.listFiles()) { String zoomLevel = null; String xCoord = null; String yCoord = null; File outDir = null; if (inFile.isFile() && isPng(inFile)) { //Quadtree zoom level is determined by the number of digits in the filename //zoomLevel = String.valueOf(inFile.getName().length()); String quadkey = quadKeyFromFilename(inFile.getName()); zoomLevel = String.valueOf(quadkey.length()); xCoord = xCoordFromQuadkey(quadkey); yCoord = yCoordFromQuadkey(quadkey); //create the output directory, if needed: outDir = new File(outputDir + “\\” + zoomLevel + “\\” + xCoord); if (!outDir.exists()){ System.out.println(“Creating directory: “ + outDir.toString()); outDir.mkdirs(); } //now copy and rename the source file File outFile = new File(outputDir + “\\” + zoomLevel + “\\” + xCoord + “\\” + yCoord + “.png”); System.out.println(“Copying “+ inFile.getName() + ” to “ + outFile.getName()); try { copyFile(inFile, outFile); } catch (Exception e){ System.out.println(“Drat, I thought it was too good to be true”); } } } /* * for each tile { * create source folder with number of digits, if doesn’t exist * * get x coord from filename * * if directory with x coord does not exist, create it * * yet y coord from filename * * copy source file to zoom/x and rename to y.png * } */ } public static boolean isPng(File file){ if (file.getName().lastIndexOf(“.png”) != –1) return true; else return false; } /* * Based on PHP script found here: * http://forum.mgmaps.com/viewtopic.php?p=11105 * function QuadKey2TileCoordinates($quadkey) { $x=0; $y=0; for ($i=0; $i<strlen($quadkey); $i++) { $x = $x*2; $y = $y*2; switch (substr($quadkey, $i, 1)) { case 0: break; case 1: $x++; break; case 2: $y++; break; case 3: $x++; $y++; break; } } return array($x,$y); } */ public static String xCoordFromQuadkey(String quadkey){ int x = 0; for (int i=0; i<quadkey.length(); i++){ x = x*2; if ((Character.getNumericValue(quadkey.charAt(i)) == 1) || (Character.getNumericValue(quadkey.charAt(i)) == 3)){ x++; } } return String.valueOf(x); } public static String yCoordFromQuadkey(String quadkey){ int y = 0; for (int i=0; i<quadkey.length(); i++){ y = y*2; if ((Character.getNumericValue(quadkey.charAt(i)) == 2) || (Character.getNumericValue(quadkey.charAt(i)) == 3)){ y++; } } return String.valueOf(y); } public static String quadKeyFromFilename(String filename){ int dotInd = filename.lastIndexOf(‘.’); // if dot is in the first position, // we are dealing with a hidden file rather than an extension return (dotInd > 0) ? filename.substring(0, dotInd) : filename; } public static void copyFile(File sourceFile, File destFile) throws IOException { if(!destFile.exists()) { destFile.createNewFile(); } FileChannel source = null; FileChannel destination = null; try { source = new FileInputStream(sourceFile).getChannel(); destination = new FileOutputStream(destFile).getChannel(); destination.transferFrom(source, 0, source.size()); } finally { if(source != null) { source.close(); } if(destination != null) { destination.close(); } } } } |