/* * Copyright (C) 2012. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 or * version 2 as published by the Free Software Foundation. * * 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. */ package uk.me.parabola.mkgmap.sea.optional; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; import java.util.zip.GZIPOutputStream; import uk.me.parabola.imgfmt.Utils; import uk.me.parabola.imgfmt.app.Coord; import uk.me.parabola.mkgmap.reader.osm.SeaGenerator; import uk.me.parabola.mkgmap.reader.osm.Way; import uk.me.parabola.splitter.BinaryMapWriter; import uk.me.parabola.splitter.Node; import uk.me.parabola.splitter.OSMWriter; import uk.me.parabola.splitter.OSMXMLWriter; class PrecompSeaSaver implements Runnable { private final AtomicBoolean finished = new AtomicBoolean(false); private final CountDownLatch finishWait; private final Map<String, String> index; private final Map<Integer, String> idMapping; private int nextId = 0; private final boolean usePbf; private final File outputDir; private final BlockingQueue<Entry<String, List<Way>>> saveQueue = new LinkedBlockingQueue<Entry<String, List<Way>>>(); public PrecompSeaSaver(File outputDir, boolean usePbf) { this.outputDir = outputDir; finishWait = new CountDownLatch(1); this.usePbf = usePbf; idMapping = new HashMap<Integer, String>(); index = new TreeMap<String, String>(); this.outputDir.mkdirs(); } public BlockingQueue<Entry<String, List<Way>>> getQueue() { return saveQueue; } private OSMWriter createWriter(int id, String key) { String[] parts = key.split(Pattern.quote("_")); int lat = Integer.valueOf(parts[0]); int lon = Integer.valueOf(parts[1]); uk.me.parabola.splitter.Area bounds = new uk.me.parabola.splitter.Area( lat, lon, lat + SeaGenerator.PRECOMP_RASTER, lon + SeaGenerator.PRECOMP_RASTER); OSMWriter writer = (usePbf ? new BinaryMapWriter(bounds, outputDir, nextId, 0) : new OSMXMLWriter(bounds, outputDir, nextId, 0)); idMapping.put(id, key); writer.initForWrite(); return writer; } public void waitForFinish() throws InterruptedException { this.finished.set(true); this.finishWait.await(); } public void run() { while (saveQueue.isEmpty() == false || finished.get() == false) { Entry<String, List<Way>> tileData = null; try { tileData = saveQueue.poll(1, TimeUnit.MINUTES); } catch (InterruptedException exp) { exp.printStackTrace(); } if (tileData != null) { int id = ++nextId; if (tileData.getValue().size() == 1) { // do not write the tile because it consists of one // natural type only // write it only to the index Way singleWay = tileData.getValue().get(0); String naturalTag = singleWay.getTag("natural"); index.put(tileData.getKey(), naturalTag); } else { String ext = (usePbf ? "pbf" : "gz"); index.put(tileData.getKey(), "sea_" + tileData.getKey() + ".osm." + ext); OSMWriter writer = createWriter(id, tileData.getKey()); Long2ObjectOpenHashMap<Long> coordIds = new Long2ObjectOpenHashMap<>(); Map<Long,uk.me.parabola.splitter.Way> pbfWays = new TreeMap<Long, uk.me.parabola.splitter.Way>(); long maxNodeId = 1; for (Way w : tileData.getValue()) { uk.me.parabola.splitter.Way pbfWay = new uk.me.parabola.splitter.Way(); pbfWay.set(w.getId()); for (Entry<String, String> tag : w .getTagEntryIterator()) { pbfWay.addTag(tag.getKey(), tag.getValue()); } for (Coord c : w.getPoints()) { Node n = new Node(); long key = Utils.coord2Long(c); Long nodeId = coordIds.get(key); if (nodeId == null) { nodeId = new Long(maxNodeId++); coordIds.put(key, nodeId); n.set(nodeId, c.getLatDegrees(), c.getLonDegrees()); try { writer.write(n); } catch (IOException exp) { exp.printStackTrace(); } } pbfWay.addRef(nodeId); } pbfWays.put(pbfWay.getId(),pbfWay); } for (uk.me.parabola.splitter.Way pbfWay : pbfWays.values()) { try { writer.write(pbfWay); } catch (IOException exp) { exp.printStackTrace(); } } writer.finishWrite(); File tileFile = new File(outputDir, String.format( "%08d.osm." + ext, id)); File precompFile = new File(outputDir, "sea_" + tileData.getKey() + ".osm." + ext); if (precompFile.exists()) { precompFile.delete(); } tileFile.renameTo(precompFile); } } } writeIndex(); finishWait.countDown(); } private void writeIndex() { try { PrintWriter indexWriter = new PrintWriter( new GZIPOutputStream(new FileOutputStream( new File(outputDir, "index.txt.gz")))); for (Entry<String, String> ind : index.entrySet()) { indexWriter.format("%s;%s\n", ind.getKey(), ind.getValue()); } indexWriter.close(); } catch (IOException exp1) { exp1.printStackTrace(); } } }