/* * Copyright 2010, 2011, 2012 mapsforge.org * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package org.mapsforge.map.writer.model; import java.io.DataInputStream; import java.io.IOException; import java.util.BitSet; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * Encapsulates the information given in the oceantiles_12.dat file. That is the information whether a given tile on * zoom level 12 is completely covered by water, land or is mixed. * * @author bross */ public final class TileInfo { private static final Logger LOGGER = Logger.getLogger(TileInfo.class.getName()); private static final String OCEAN_TILES_FILE = "oceantiles_12.dat"; private static final byte SEA = 0x2; /** * The zoom level for which the tile info is valid. */ public static final byte TILE_INFO_ZOOMLEVEL = 0xC; private static final byte BITMASK = 0x3; // 4096 * 4096 / 4 (2 bits for each tile) private static final int N_BYTES = 0x400000; // 4096 * 4096 = number of tiles on zoom level 12 private static final int N_BITS = 0x1000000; private final BitSet seaTileInfo = new BitSet(N_BITS); private TileInfo(String strInputFile) { try { DataInputStream dis = new DataInputStream(TileInfo.class.getClassLoader().getResourceAsStream(strInputFile)); byte currentByte; long start = System.currentTimeMillis(); for (int i = 0; i < N_BYTES; i++) { currentByte = dis.readByte(); if (((currentByte >> 6) & BITMASK) == SEA) { this.seaTileInfo.set(i * 4); } if (((currentByte >> 4) & BITMASK) == SEA) { this.seaTileInfo.set(i * 4 + 1); } if (((currentByte >> 2) & BITMASK) == SEA) { this.seaTileInfo.set(i * 4 + 2); } if ((currentByte & BITMASK) == SEA) { this.seaTileInfo.set(i * 4 + 3); } } LOGGER.fine("loading of tile info data took " + (System.currentTimeMillis() - start) + " ms"); } catch (IOException e) { LOGGER.log(Level.SEVERE, "error loading tile info from file " + strInputFile); } } /** * @return the singleton which encapsulates the oceantile_12.dat information */ public static TileInfo getInstance() { return new TileInfo(OCEAN_TILES_FILE); } /** * Checks if a tile is completely covered by water. <b>Important notice:</b> The method may produce false negatives * on higher zoom levels than 12. * * @param tc * tile given as TileCoordinate * @return true if the tile is completely covered by water, false if the associated tile(s) on zoom level 12 is(are) * not completely covered by water. */ public boolean isWaterTile(TileCoordinate tc) { List<TileCoordinate> tiles = tc.translateToZoomLevel(TILE_INFO_ZOOMLEVEL); for (TileCoordinate tile : tiles) { if (!this.seaTileInfo.get(tile.getY() * 4096 + tile.getX())) { return false; } } return true; } }