Hi,

attached is the generator for precompiled sea data.

Additionally you need some geotools libs (they are not downloaded by ivy). You can download it from http://sourceforge.net/projects/geotools/files/
The required libs are:
commons-pool-1.5.4.jar
gt-api-2.7.5.jar
gt-cql-2.7.5.jar
gt-data-2.7.5.jar
gt-main-2.7.5.jar
gt-metadata-2.7.5.jar
gt-opengis-2.7.5.jar
gt-referencing-2.7.5.jar
gt-shapefile-2.7.5.jar
jsr-275-1.0-beta-2.jar
jts-1.11.jar
vecmath-1.3.2.jar


The generator can be started with
java -cp <mkgmap classes dir> uk.me.parabola.mkgmap.sea.optional.PrecompSeaGenerator <shapefilename> <projection> <outputdir>

shapefilename: the filename of the .shp file
projection: WGS84 or any EPSG:xxxx
outputdir: the directory to store the precompiled files

The generator is not included in the mkgmap.jar file because the geotools libs are not automatically downloaded by ivy. If anyone can give an ivy dependency for the libs it is possible to change that.

There are some performance settings that might be changed on your computer to better meet the memory/CPU settings of your computer. Have a look at the PrecompSeaGenerator constructor. The defined settings are ok for 3gb memory (-Xmx3g).

WanMil
Index: src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaGenerator.java
===================================================================
--- src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaGenerator.java	(revision 0)
+++ src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaGenerator.java	(revision 0)
@@ -0,0 +1,350 @@
+/*
+ * 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 java.awt.Rectangle;
+import java.awt.geom.Area;
+import java.awt.geom.Path2D;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicLong;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.mkgmap.reader.osm.SeaGenerator;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+import org.geotools.data.DataStore;
+import org.geotools.data.DataStoreFinder;
+import org.geotools.data.simple.SimpleFeatureCollection;
+import org.geotools.data.simple.SimpleFeatureSource;
+import org.geotools.feature.FeatureIterator;
+import org.geotools.filter.text.cql2.CQLException;
+import org.geotools.geometry.jts.JTS;
+import org.geotools.referencing.CRS;
+import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.opengis.feature.Feature;
+import org.opengis.feature.GeometryAttribute;
+import org.opengis.geometry.MismatchedDimensionException;
+import org.opengis.referencing.FactoryException;
+import org.opengis.referencing.NoSuchAuthorityCodeException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.TransformException;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Geometry;
+
+public class PrecompSeaGenerator {
+
+	private final AtomicLong osmId = new AtomicLong();
+
+	public final ExecutorService service;
+
+	private static class ProgressPrinter extends Thread {
+		private final CountDownLatch countdown;
+
+		public ProgressPrinter(CountDownLatch countdown) {
+			super("ProgressPrinter");
+			this.countdown = countdown;
+			setDaemon(true);
+		}
+
+		public void run() {
+			long count = 0;
+			do {
+				count = countdown.getCount();
+				System.out.println(count + " tiles remaining");
+				try {
+					Thread.sleep(10000);
+				} catch (InterruptedException exp) {
+				}
+			} while (count > 0);
+		}
+	}
+
+	private Area convertToArea(Geometry geometry) {
+		Coordinate[] c = geometry.getCoordinates();
+		Path2D.Double path = new Path2D.Double();
+		path.moveTo(Utils.toMapUnit(c[0].x), Utils.toMapUnit(c[0].y));
+		for (int n = 1; n < c.length; n++) {
+			path.lineTo(Utils.toMapUnit(c[n].x), Utils.toMapUnit(c[n].y));
+		}
+		path.closePath();
+		return new Area(path);
+	}
+
+	private static int getRasterStart(int value) {
+		int rem = value % SeaGenerator.PRECOMP_RASTER;
+		if (rem == 0) {
+			return value;
+		} else if (value >= 0) {
+			return value - rem;
+		} else {
+			return value - SeaGenerator.PRECOMP_RASTER - rem;
+		}
+	}
+
+	private final File shapeFile;
+	private final File outputDir;
+
+	private SimpleFeatureCollection shapeCollection;
+	private FeatureIterator shapeIterator;
+
+	private final MathTransform transformation;
+	private boolean usePbfFormat;
+	private int tilesPerCycle;
+
+	public PrecompSeaGenerator(File shapeFile, String shapeCRS, File outputDir)
+			throws NoSuchAuthorityCodeException, FactoryException {
+		this.shapeFile = shapeFile;
+		this.outputDir = outputDir;
+		this.transformation = createTransformation(shapeCRS);
+		
+		this.service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
+		this.usePbfFormat = true;
+		this.tilesPerCycle = 10 * 512;
+	}
+
+	public void setUsePbfFormat(boolean usePbf) {
+		this.usePbfFormat = usePbf;
+	}
+
+	private MathTransform createTransformation(String shapeCRS)
+			throws NoSuchAuthorityCodeException, FactoryException {
+		if ("WGS84".equals(shapeCRS)) {
+			return null;
+		}
+		CoordinateReferenceSystem crsInShapefile = CRS.decode(shapeCRS);
+		CoordinateReferenceSystem targetCRS = DefaultGeographicCRS.WGS84;
+		boolean lenient = true; // allow for some error due to different datums
+		return CRS.findMathTransform(crsInShapefile, targetCRS, lenient);
+	}
+
+	private Geometry transformToWGS84(Geometry geometry)
+			throws MismatchedDimensionException, TransformException {
+		if (transformation == null) {
+			return geometry;
+		} else {
+			return JTS.transform(geometry, transformation);
+		}
+	}
+
+	private List<uk.me.parabola.imgfmt.app.Area> getTiles() {
+		uk.me.parabola.imgfmt.app.Area earth = new uk.me.parabola.imgfmt.app.Area(
+				-90.0d, -180.0d, 90.0d, 180.0d);
+		return getTiles(earth);
+	}
+
+	private List<uk.me.parabola.imgfmt.app.Area> getTiles(
+			uk.me.parabola.imgfmt.app.Area wholeArea) {
+		int minLat = wholeArea.getMinLat();
+		int maxLat = wholeArea.getMaxLat();
+		int minLon = wholeArea.getMinLong();
+		int maxLon = wholeArea.getMaxLong();
+
+		List<uk.me.parabola.imgfmt.app.Area> tiles = new ArrayList<uk.me.parabola.imgfmt.app.Area>();
+		for (int lon = getRasterStart(minLon); lon < maxLon; lon += SeaGenerator.PRECOMP_RASTER) {
+			for (int lat = getRasterStart(minLat); lat < maxLat; lat += SeaGenerator.PRECOMP_RASTER) {
+				uk.me.parabola.imgfmt.app.Area tile = new uk.me.parabola.imgfmt.app.Area(
+						Math.max(lat, minLat), Math.max(lon, minLon), Math.min(
+								lat + SeaGenerator.PRECOMP_RASTER, maxLat),
+						Math.min(lon + SeaGenerator.PRECOMP_RASTER, maxLon));
+				tiles.add(tile);
+			}
+		}
+		return tiles;
+	}
+
+	private List<PrecompSeaMerger> createMergers(
+			Collection<uk.me.parabola.imgfmt.app.Area> tiles,
+			CountDownLatch tilesCountdown,
+			BlockingQueue<Entry<String, List<Way>>> saveQueue) {
+		List<PrecompSeaMerger> mergers = new ArrayList<PrecompSeaMerger>();
+
+		for (uk.me.parabola.imgfmt.app.Area bounds : tiles) {
+
+			Rectangle mergeBounds = new Rectangle(bounds.getMinLong(),
+					bounds.getMinLat(), bounds.getWidth(), bounds.getHeight());
+			String tileKey = bounds.getMinLat() + "_" + bounds.getMinLong();
+
+			PrecompSeaMerger merger = new PrecompSeaMerger(mergeBounds,
+					tileKey, tilesCountdown, saveQueue);
+			merger.setIdGenerator(osmId);
+			merger.setExecutorService(service);
+			mergers.add(merger);
+		}
+		return mergers;
+	}
+
+	private void createShapefileAccess() throws IOException {
+		Map map = new HashMap();
+		map.put("url", shapeFile.toURL());
+		DataStore dataStore = DataStoreFinder.getDataStore(map);
+		String typeName = dataStore.getTypeNames()[0];
+
+		SimpleFeatureSource source = dataStore.getFeatureSource(typeName);
+		shapeCollection = source.getFeatures();
+	}
+
+	private void openShapefile() {
+		shapeIterator = shapeCollection.features();
+	}
+
+	private void closeShapefile() {
+		shapeIterator.close();
+		shapeIterator = null;
+	}
+
+	private Geometry readNextPolygon() {
+		if (shapeIterator.hasNext()) {
+			Feature feature = shapeIterator.next();
+			GeometryAttribute geom = feature.getDefaultGeometryProperty();
+			Geometry poly = (Geometry) geom.getValue();
+			try {
+				return transformToWGS84(poly);
+			} catch (Exception exp) {
+				System.err.println(exp);
+				return null;
+			}
+		} else {
+			return null;
+		}
+	}
+
+	public void runSeaGeneration() throws MismatchedDimensionException,
+			TransformException, IOException, InterruptedException {
+		createShapefileAccess();
+
+		List<uk.me.parabola.imgfmt.app.Area> remainingTiles = getTiles();
+
+		CountDownLatch tilesCountdown = new CountDownLatch(
+				remainingTiles.size());
+		new ProgressPrinter(tilesCountdown).start();
+
+		PrecompSeaSaver precompSaver = new PrecompSeaSaver(outputDir,
+				usePbfFormat);
+		new Thread(precompSaver, "SaveThread").start();
+
+		// perform several cycles which is necessary to reduce memory
+		// requirements
+		while (remainingTiles.isEmpty() == false) {
+
+			List<uk.me.parabola.imgfmt.app.Area> tiles = new ArrayList<uk.me.parabola.imgfmt.app.Area>();
+			tiles.addAll(remainingTiles.subList(0,
+					Math.min(tilesPerCycle, remainingTiles.size())));
+			remainingTiles.subList(0,
+					Math.min(tilesPerCycle, remainingTiles.size())).clear();
+
+			Area tileArea = new Area();
+
+			List<PrecompSeaMerger> mergers = createMergers(tiles,
+					tilesCountdown, precompSaver.getQueue());
+			for (PrecompSeaMerger m : mergers) {
+				tileArea.add(new Area(m.getTileBounds()));
+				service.execute(m);
+			}
+
+			openShapefile();
+
+			int s = 0;
+			long lastInfo = System.currentTimeMillis();
+			Geometry wgs84Poly = null;
+			while ((wgs84Poly = readNextPolygon()) != null) {
+
+				if (wgs84Poly.getNumGeometries() != 1) {
+					System.err.println("Polygon from shapefile has "
+							+ wgs84Poly.getNumGeometries()
+							+ " geometries. Only one geometry is supported.");
+					System.err.println("Skip polygon.");
+					continue;
+				}
+
+				Geometry bounds = wgs84Poly.getEnvelope();
+				if (bounds.isEmpty()) {
+					System.err.println("Empty or non polygon: " + bounds);
+				} else {
+					Area polyBounds = convertToArea(bounds);
+					if (polyBounds.intersects(tileArea.getBounds2D())) {
+						Area polyAsArea = convertToArea(wgs84Poly
+								.getGeometryN(0));
+						for (PrecompSeaMerger mThread : mergers) {
+							if (mThread.getTileBounds().intersects(
+									polyAsArea.getBounds2D())) {
+								try {
+									mThread.getQueue().put(polyAsArea);
+								} catch (InterruptedException exp) {
+									exp.printStackTrace();
+								}
+							}
+						}
+					}
+
+					if ((++s) % 50000 == 0
+							|| System.currentTimeMillis() - lastInfo > 30000) {
+						System.out.println("Worked out " + (s++) + " polygons");
+						lastInfo = System.currentTimeMillis();
+					}
+
+				}
+			}
+			closeShapefile();
+
+			System.out.println("Reading shapefile finished");
+
+			for (PrecompSeaMerger mThread : mergers) {
+				mThread.signalInputComplete();
+			}
+
+			while (tilesCountdown.getCount() > remainingTiles.size()
+					+ 2*tilesPerCycle) {
+				Thread.sleep(50L);
+			}
+		}
+		tilesCountdown.await();
+		precompSaver.waitForFinish();
+		service.shutdown();
+	}
+
+	/**
+	 * @param args
+	 * @throws InterruptedException
+	 */
+
+	public static void main(String[] args) throws MismatchedDimensionException,
+			TransformException, IOException, FactoryException, CQLException,
+			InterruptedException {
+		long t1 = System.currentTimeMillis();
+		
+		File shapeFile = new File(args[0]);
+		String shapeCRS = args[1];
+		File outputDir = new File(args[2]);
+
+		PrecompSeaGenerator seaGenerator = new PrecompSeaGenerator(shapeFile,
+				shapeCRS, outputDir);
+		seaGenerator.runSeaGeneration();
+
+		System.out.println("Generation took "+(System.currentTimeMillis()-t1)+" ms");
+		
+	}
+}
Index: src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaMerger.java
===================================================================
--- src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaMerger.java	(revision 0)
+++ src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaMerger.java	(revision 0)
@@ -0,0 +1,200 @@
+/*
+ * 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 java.awt.geom.Area;
+import java.awt.geom.Rectangle2D;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.reader.osm.GeneralRelation;
+import uk.me.parabola.mkgmap.reader.osm.MultiPolygonRelation;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.Java2DConverter;
+
+class PrecompSeaMerger implements Runnable {
+	private final MergeData mergeData;
+	private final CountDownLatch signal;
+	private final BlockingQueue<Entry<String, List<Way>>> saveQueue;
+	private AtomicLong idGenerator;
+	private ExecutorService service;
+
+	static class MergeData {
+		public final Rectangle2D bounds;
+		public final BlockingQueue<Area> toMerge;
+		public final AtomicBoolean ready = new AtomicBoolean(false);
+		public Area tmpLandArea = new Area();
+		public final Area landArea = new Area();
+		private final String key;
+
+		public MergeData(Rectangle2D bounds, String key) {
+			this.key = key;
+			this.bounds = bounds;
+			toMerge = new LinkedBlockingQueue<Area>();
+		}
+
+		public String getKey() {
+			return key;
+		}
+
+	}
+
+	public PrecompSeaMerger(Rectangle2D bounds, String key,
+			CountDownLatch signal,
+			BlockingQueue<Entry<String, List<Way>>> saveQueue) {
+		this.mergeData = new MergeData(bounds, key);
+		this.signal = signal;
+		this.saveQueue = saveQueue;
+		this.idGenerator = new AtomicLong();
+	}
+
+	public MergeData getMergeData() {
+		return mergeData;
+	}
+
+	public BlockingQueue<Area> getQueue() {
+		return mergeData.toMerge;
+	}
+
+	public void signalInputComplete() {
+		mergeData.ready.set(true);
+	}
+
+	public void setIdGenerator(AtomicLong idGenerator) {
+		this.idGenerator = idGenerator;
+	}
+
+	public void setExecutorService(ExecutorService service) {
+		this.service = service;
+	}
+
+	public Rectangle2D getTileBounds() {
+		return mergeData.bounds;
+	}
+
+	private List<Way> convertToWays(Area a, String naturalTag) {
+		List<List<Coord>> pointLists = Java2DConverter.areaToShapes(a);
+		List<Way> ways = new ArrayList<Way>(pointLists.size());
+		for (List<Coord> points : pointLists) {
+			Way w = new Way(idGenerator.incrementAndGet(), points);
+			w.addTag("natural", naturalTag);
+			ways.add(w);
+		}
+		return ways;
+	}
+
+	public void run() {
+		Area merge = null;
+		try {
+			merge = mergeData.toMerge.poll(5, TimeUnit.MILLISECONDS);
+		} catch (InterruptedException exp) {
+			exp.printStackTrace();
+		}
+		int merges = 0;
+		while (merge != null) {
+			Area landClipped = new Area(mergeData.bounds);
+			landClipped.intersect(merge);
+			mergeData.tmpLandArea.add(landClipped);
+			merges++;
+			if (merges % 500 == 0) {
+				mergeData.landArea.add(mergeData.tmpLandArea);
+				mergeData.tmpLandArea = new Area();
+			}
+
+			if (merges % 500 == 0) {
+				break;
+			}
+			merge = mergeData.toMerge.poll();
+		}
+
+		if (mergeData.ready.get() == false
+				|| mergeData.toMerge.isEmpty() == false) {
+			// repost the merge thread
+			service.execute(this);
+			return;
+		}
+
+		mergeData.landArea.add(mergeData.tmpLandArea);
+		mergeData.tmpLandArea = null;
+
+		List<Way> ways = convertToWays(mergeData.landArea, "land");
+
+		if (ways.isEmpty()) {
+			ways.addAll(convertToWays(new Area(mergeData.bounds), "sea"));
+		} else {
+			Map<Long, Way> landWays = new HashMap<Long, Way>();
+			List<List<Coord>> landParts = Java2DConverter
+					.areaToShapes(mergeData.landArea);
+			for (List<Coord> landPoints : landParts) {
+				Way landWay = new Way(idGenerator.incrementAndGet(), landPoints);
+				landWays.put(landWay.getId(), landWay);
+			}
+
+			List<Coord> seaCoords = new ArrayList<Coord>(5);
+			seaCoords.add(new Coord(-90.0d, -180.0d));
+			seaCoords.add(new Coord(90.0d, -180.0d));
+			seaCoords.add(new Coord(90.0d, 180.0d));
+			seaCoords.add(new Coord(-90.0d, 180.0d));
+			seaCoords.add(new Coord(-90.0d, -180.0d));
+			Way seaWay = new Way(idGenerator.incrementAndGet(), seaCoords);
+			landWays.put(seaWay.getId(), seaWay);
+
+			Relation rel = new GeneralRelation(idGenerator.incrementAndGet());
+			for (Way w : landWays.values()) {
+				rel.addElement((w == seaWay ? "outer" : "inner"), w);
+			}
+
+			MultiPolygonRelation mpr = new MultiPolygonRelation(rel, landWays,
+					Java2DConverter.createBbox(new Area(mergeData.bounds)));
+			mpr.addTag("type", "multipolygon");
+			mpr.addTag("natural", "sea");
+			mpr.processElements();
+
+			for (Way w : landWays.values()) {
+				if (MultiPolygonRelation.STYLE_FILTER_POLYGON.equals(w
+						.getTag(MultiPolygonRelation.STYLE_FILTER_TAG))) {
+					String tag = w.getTag("natural");
+					if ("sea".equals(tag) == false) {
+						continue;
+					}
+					w.deleteTag(MultiPolygonRelation.STYLE_FILTER_TAG);
+					w.deleteTag(MultiPolygonRelation.MP_CREATED_TAG);
+					ways.add(w);
+				}
+			}
+		}
+
+		try {
+			saveQueue.put(new SimpleEntry<String, List<Way>>(
+					mergeData.getKey(), ways));
+		} catch (InterruptedException exp) {
+			exp.printStackTrace();
+		}
+
+		signal.countDown();
+	}
+}
\ No newline at end of file
Index: src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaSaver.java
===================================================================
--- src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaSaver.java	(revision 0)
+++ src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaSaver.java	(revision 0)
@@ -0,0 +1,193 @@
+/*
+ * 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 java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.Map.Entry;
+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.concurrent.atomic.AtomicLong;
+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 AtomicLong idGenerator;
+	
+	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.idGenerator = new AtomicLong();
+		this.outputDir.mkdirs();
+	}
+	
+	public void setIdGenerator(AtomicLong idGenerator) {
+		this.idGenerator = idGenerator;
+	}
+	
+	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)
+				: new OSMXMLWriter(bounds, outputDir));
+		idMapping.put(id, key);
+		writer.initForWrite(nextId, 0);
+		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());
+
+					Map<Coord, Long> coordIds = new HashMap<Coord, Long>();
+
+					List<uk.me.parabola.splitter.Way> pbfWays = new ArrayList<uk.me.parabola.splitter.Way>();
+
+					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
+								.getEntryIteratable()) {
+							pbfWay.addTag(tag.getKey(), tag.getValue());
+						}
+						for (Coord c : w.getPoints()) {
+							Node n = new Node();
+							Long nodeId = coordIds.get(c);
+							if (nodeId == null) {
+								nodeId = idGenerator.incrementAndGet();
+								coordIds.put(c, nodeId);
+								n.set(nodeId,
+										Utils.toDegrees(c.getLatitude()),
+										Utils.toDegrees(c.getLongitude()));
+								try {
+									writer.write(n);
+								} catch (IOException exp) {
+									exp.printStackTrace();
+								}
+							}
+							pbfWay.addRef(nodeId);
+						}
+						pbfWays.add(pbfWay);
+					}
+					for (uk.me.parabola.splitter.Way pbfWay : pbfWays) {
+						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();
+		}
+	}
+}
\ No newline at end of file
Index: src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java	(revision 2302)
+++ src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java	(working copy)
@@ -74,7 +74,8 @@
 	private StyleImpl fbRules;
 	
 	/** The size (lat and long) of the precompiled sea tiles */
-	private final static int PRECOMP_RASTER = 1 << 15;
+	public final static int PRECOMP_RASTER = 1 << 15;
+	
 	/**
 	 * The directory of the precompiled sea tiles or <code>null</code> if
 	 * precompiled sea should not be used.
Index: build.xml
===================================================================
--- build.xml	(revision 2302)
+++ build.xml	(working copy)
@@ -227,7 +227,7 @@
 		<javac srcdir="${src}" destdir="${build.classes}" debug="true">
 			<include name="**/*.java" />
 			<classpath refid="main"/>
-			<exclude name="**/reader/dem/optional/*.java"/>
+			<exclude name="**/optional/*.java"/>
 		</javac>
 	</target>
 
_______________________________________________
mkgmap-dev mailing list
mkgmap-dev@lists.mkgmap.org.uk
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to