/* * This file is part of JGrasstools (http://www.jgrasstools.org) * (C) HydroloGIS - www.hydrologis.com * * JGrasstools is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.jgrasstools.nww.layers.defaults.raster; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import javax.imageio.ImageIO; import org.jgrasstools.gears.utils.files.FileUtilities; import org.jgrasstools.nww.layers.defaults.NwwLayer; import org.jgrasstools.nww.utils.NwwUtilities; import org.jgrasstools.nww.utils.cache.CacheUtils; import org.mapsforge.core.model.BoundingBox; import org.mapsforge.core.model.LatLong; import org.mapsforge.map.awt.graphics.AwtGraphicFactory; import org.mapsforge.map.controller.FrameBufferController; import org.mapsforge.map.datastore.MultiMapDataStore; import org.mapsforge.map.datastore.MultiMapDataStore.DataPolicy; import org.mapsforge.map.layer.cache.InMemoryTileCache; import org.mapsforge.map.layer.labels.TileBasedLabelStore; import org.mapsforge.map.layer.renderer.DatabaseRenderer; import org.mapsforge.map.layer.renderer.MapWorkerPool; import org.mapsforge.map.model.DisplayModel; import org.mapsforge.map.reader.MapFile; import org.mapsforge.map.reader.ReadBuffer; import org.mapsforge.map.rendertheme.InternalRenderTheme; import org.mapsforge.map.rendertheme.rule.RenderThemeFuture; import com.vividsolutions.jts.geom.Coordinate; import gov.nasa.worldwind.avlist.AVKey; import gov.nasa.worldwind.avlist.AVList; import gov.nasa.worldwind.avlist.AVListImpl; import gov.nasa.worldwind.geom.Angle; import gov.nasa.worldwind.geom.LatLon; import gov.nasa.worldwind.geom.Sector; import gov.nasa.worldwind.layers.mercator.MercatorSector; import gov.nasa.worldwind.util.LevelSet; import gov.nasa.worldwind.util.Tile; import gov.nasa.worldwind.util.TileUrlBuilder; /** * Procedural layer for mapsforge files * * @author Andrea Antonello (www.hydrologis.com) */ public class MapsforgeNwwLayer extends BasicMercatorTiledImageLayer implements NwwLayer { private String layerName = "unknown layer"; private static final int TILESIZE = 1024; private Coordinate centerCoordinate; public MapsforgeNwwLayer(String layerName, File[] mapsforgeFiles, Integer tileSize, Float scaleFactor) throws Exception { super(makeLevels(layerName, getTilegenerator(mapsforgeFiles, tileSize, scaleFactor), tileSize)); this.layerName = layerName; this.setUseTransparentTextures(true); MultiMapDataStore mapDatabase = new MultiMapDataStore(DataPolicy.RETURN_ALL); for (int i = 0; i < mapsforgeFiles.length; i++) mapDatabase.addMapDataStore(new MapFile(mapsforgeFiles[i]), false, false); BoundingBox boundingBox = mapDatabase.boundingBox(); LatLong centerPoint = boundingBox.getCenterPoint(); centerCoordinate = new Coordinate(centerPoint.longitude, centerPoint.latitude); mapDatabase.close(); } private static OsmTilegenerator getTilegenerator(File[] mapsforgeFiles, Integer tileSize, Float scaleFactor) { if (tileSize == null || tileSize < 256) { tileSize = TILESIZE; } if (scaleFactor == null) scaleFactor = 1.5f; MapWorkerPool.NUMBER_OF_THREADS = 4; // Map buffer size ReadBuffer.setMaximumBufferSize(6500000); // Square frame buffer FrameBufferController.setUseSquareFrameBuffer(false); DisplayModel model = new DisplayModel(); model.setUserScaleFactor(scaleFactor); model.setFixedTileSize(tileSize); DataPolicy dataPolicy = DataPolicy.RETURN_ALL; MultiMapDataStore mapDatabase = new MultiMapDataStore(dataPolicy); for (int i = 0; i < mapsforgeFiles.length; i++) mapDatabase.addMapDataStore(new MapFile(mapsforgeFiles[i]), false, false); InMemoryTileCache tileCache = new InMemoryTileCache(200); DatabaseRenderer renderer = new DatabaseRenderer(mapDatabase, AwtGraphicFactory.INSTANCE, tileCache, new TileBasedLabelStore(tileCache.getCapacityFirstLevel()), true, true); InternalRenderTheme xmlRenderTheme = InternalRenderTheme.DEFAULT; RenderThemeFuture theme = new RenderThemeFuture(AwtGraphicFactory.INSTANCE, xmlRenderTheme, model); // super important!! without the following line, all rendering // activities will block until the theme is created. new Thread(theme).start(); // TODO get back external themes // DatabaseRenderer dbRenderer = null; // XmlRenderTheme xmlRenderTheme = null; // DisplayModel displayModel = null; // if (mapsforgeFile.exists()) { // mapDatabase.openFile(mapsforgeFile); // dbRenderer = new DatabaseRenderer(mapDatabase, graphicFactory); // // String mapName = // FileUtilities.getNameWithoutExtention(mapsforgeFiles[0]); // File xmlStyleFile = new File(mapsforgeFiles[0].getParentFile(), // mapName + ".xml"); // if (xmlStyleFile.exists()) { // try { // xmlRenderTheme = new ExternalRenderTheme(xmlStyleFile); // } catch (Exception e) { // xmlRenderTheme = InternalRenderTheme.OSMARENDER; // } // } else { // xmlRenderTheme = InternalRenderTheme.OSMARENDER; // } // displayModel = new DisplayModel(); // displayModel.setUserScaleFactor(tileSize / 256f); // } return new OsmTilegenerator(mapDatabase, renderer, theme, model, tileSize); } private static LevelSet makeLevels(String layerName, OsmTilegenerator osmTilegenerator, Integer tileSize) throws MalformedURLException { AVList params = new AVListImpl(); String cacheRelativePath = "mapsforge/" + layerName + "-tiles"; if (tileSize == null || tileSize < 256) { tileSize = TILESIZE; } int finalTileSize = tileSize; params.setValue(AVKey.URL, cacheRelativePath); params.setValue(AVKey.TILE_WIDTH, finalTileSize); params.setValue(AVKey.TILE_HEIGHT, finalTileSize); params.setValue(AVKey.DATA_CACHE_NAME, cacheRelativePath); params.setValue(AVKey.SERVICE, "*"); params.setValue(AVKey.DATASET_NAME, "*"); params.setValue(AVKey.FORMAT_SUFFIX, ".png"); params.setValue(AVKey.NUM_LEVELS, 22); params.setValue(AVKey.NUM_EMPTY_LEVELS, 0); params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, new LatLon(Angle.fromDegrees(22.5d), Angle.fromDegrees(45d))); params.setValue(AVKey.SECTOR, new MercatorSector(-1.0, 1.0, Angle.NEG180, Angle.POS180)); File cacheRoot = CacheUtils.getCacheRoot(); final File cacheFolder = new File(cacheRoot, cacheRelativePath); if (!cacheFolder.exists()) { cacheFolder.mkdirs(); } params.setValue(AVKey.TILE_URL_BUILDER, new TileUrlBuilder() { public URL getURL(Tile tile, String altImageFormat) throws MalformedURLException { int zoom = tile.getLevelNumber() + 3; Sector sector = tile.getSector(); double north = sector.getMaxLatitude().degrees; double south = sector.getMinLatitude().degrees; double east = sector.getMaxLongitude().degrees; double west = sector.getMinLongitude().degrees; double centerX = west + (east - west) / 2.0; double centerY = south + (north - south) / 2.0; int[] tileNumber = NwwUtilities.getTileNumber(centerY, centerX, zoom); int x = tileNumber[0]; int y = tileNumber[1]; File tileImageFolderFile = new File(cacheFolder, zoom + File.separator + x); if (!tileImageFolderFile.exists()) { tileImageFolderFile.mkdirs(); } File imgFile = new File(tileImageFolderFile, y + ".png"); try { if (!imgFile.exists()) { BufferedImage bImg = osmTilegenerator.getImage(zoom, x, y); // PrintUtilities.printRenderedImageData(bImg); ImageIO.write(bImg, "png", imgFile); } return imgFile.toURI().toURL(); } catch (IOException e) { return null; } } }); return new LevelSet(params); } public String toString() { return layerName; } @Override public Coordinate getCenter() { return centerCoordinate; } }