kopia lustrzana https://github.com/onthegomap/planetiler
				
				
				
			scaffold mbtiles
							rodzic
							
								
									1273c6bd9b
								
							
						
					
					
						commit
						890c3c150d
					
				|  | @ -83,4 +83,17 @@ public class GeoUtils { | |||
|     long y = (long) (worldY * QUANTIZED_WORLD_SIZE); | ||||
|     return (x << 32) | y; | ||||
|   } | ||||
| 
 | ||||
|   public static int z(int key) { | ||||
|     int result = key >> 28; | ||||
|     return result < 0 ? 16 + result : result; | ||||
|   } | ||||
| 
 | ||||
|   public static int x(int key) { | ||||
|     return (key >> 14) & ((1 << 14) - 1); | ||||
|   } | ||||
| 
 | ||||
|   public static int y(int key) { | ||||
|     return (key) & ((1 << 14) - 1); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,11 +1,100 @@ | |||
| package com.onthegomap.flatmap; | ||||
| 
 | ||||
| import static com.onthegomap.flatmap.GeoUtils.x; | ||||
| import static com.onthegomap.flatmap.GeoUtils.y; | ||||
| import static com.onthegomap.flatmap.GeoUtils.z; | ||||
| 
 | ||||
| import com.onthegomap.flatmap.collections.MergeSortFeatureMap; | ||||
| import com.onthegomap.flatmap.collections.MergeSortFeatureMap.TileFeatures; | ||||
| import com.onthegomap.flatmap.stats.Stats; | ||||
| import com.onthegomap.flatmap.worker.Topology; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.util.concurrent.atomic.AtomicLong; | ||||
| import java.util.function.Consumer; | ||||
| import java.util.function.Supplier; | ||||
| import java.util.zip.GZIPOutputStream; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| 
 | ||||
| public class MbtilesWriter { | ||||
| 
 | ||||
|   public static void writeOutput(MergeSortFeatureMap features, File output, FlatMapConfig threads) { | ||||
|   private final AtomicLong featuresProcessed = new AtomicLong(0); | ||||
|   private final AtomicLong memoizedTiles = new AtomicLong(0); | ||||
|   private final AtomicLong tiles = new AtomicLong(0); | ||||
|   private final Stats stats; | ||||
| 
 | ||||
|   private MbtilesWriter(Stats stats) { | ||||
|     this.stats = stats; | ||||
|   } | ||||
| 
 | ||||
|   private static final Logger LOGGER = LoggerFactory.getLogger(MbtilesWriter.class); | ||||
| 
 | ||||
|   private static record RenderedTile(int tile, byte[] contents) { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   public static void writeOutput(long featureCount, MergeSortFeatureMap features, File output, FlatMapConfig config) { | ||||
|     Stats stats = config.stats(); | ||||
|     output.delete(); | ||||
|     MbtilesWriter writer = new MbtilesWriter(config.stats()); | ||||
| 
 | ||||
|     var topology = Topology.readFromIterator("mbtiles_reader", stats, features.getAll()) | ||||
|       .addBuffer("mbtiles_reader_queue", 50_000, 1_000) | ||||
|       .addWorker("mbtiles_encoder", config.threads(), writer::tileEncoder) | ||||
|       .addBuffer("mbtiles_writer_queue", 50_000, 1_000) | ||||
|       .sinkTo("mbtiles_writer", 1, writer::tileWriter); | ||||
| 
 | ||||
|     var loggers = new ProgressLoggers("mbtiles") | ||||
|       .addRatePercentCounter("features", featureCount, writer.featuresProcessed) | ||||
|       .addRateCounter("tiles", writer.tiles) | ||||
|       .addFileSize(output) | ||||
|       .add(" features ").addFileSize(features::getStorageSize) | ||||
|       .addProcessStats() | ||||
|       .addTopologyStats(topology); | ||||
| 
 | ||||
|     topology.awaitAndLog(loggers, config.logIntervalSeconds()); | ||||
|   } | ||||
| 
 | ||||
|   public void tileEncoder(Supplier<TileFeatures> prev, Consumer<RenderedTile> next) throws Exception { | ||||
|     MergeSortFeatureMap.TileFeatures tileFeatures, last = null; | ||||
|     byte[] lastBytes = null, lastEncoded = null; | ||||
|     while ((tileFeatures = prev.get()) != null) { | ||||
|       featuresProcessed.addAndGet(tileFeatures.getNumFeatures()); | ||||
|       byte[] bytes, encoded; | ||||
|       int zoom = z(tileFeatures.getTileId()); | ||||
|       if (tileFeatures.hasSameContents(last)) { | ||||
|         bytes = lastBytes; | ||||
|         encoded = lastEncoded; | ||||
|         memoizedTiles.incrementAndGet(); | ||||
|       } else { | ||||
|         VectorTile en = tileFeatures.getTile(); | ||||
|         encoded = en.encode(); | ||||
|         bytes = gzipCompress(encoded); | ||||
|         last = tileFeatures; | ||||
|         lastEncoded = encoded; | ||||
|         lastBytes = bytes; | ||||
|         if (encoded.length > 1_000_000) { | ||||
|           LOGGER.warn("Tile " + zoom + "/" + x(tileFeatures.getTileId()) + "/" + y(tileFeatures.getTileId()) + " " | ||||
|             + encoded.length / 1024 + "kb uncompressed"); | ||||
|         } | ||||
|       } | ||||
|       stats.encodedTile(zoom, encoded.length); | ||||
|       next.accept(new RenderedTile(tileFeatures.getTileId(), bytes)); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private void tileWriter(Supplier<RenderedTile> prev) throws Exception { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   private static byte[] gzipCompress(byte[] uncompressedData) throws IOException { | ||||
|     var bos = new ByteArrayOutputStream(uncompressedData.length); | ||||
|     try (var gzipOS = new GZIPOutputStream(bos)) { | ||||
|       gzipOS.write(uncompressedData); | ||||
|     } | ||||
|     return bos.toByteArray(); | ||||
|   } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -89,7 +89,8 @@ public class OpenMapTilesMain { | |||
| 
 | ||||
|     try (var osmReader = new OpenStreetMapReader(osmInputFile, nodeLocations, stats)) { | ||||
|       stats.time("osm_pass1", () -> osmReader.pass1(config)); | ||||
|       stats.time("osm_pass2", () -> osmReader.pass2(renderer, featureMap, config)); | ||||
|       stats | ||||
|         .time("osm_pass2", () -> osmReader.pass2(renderer, featureMap, Math.max(threads / 4, 1), threads - 1, config)); | ||||
|     } | ||||
| 
 | ||||
|     LOGGER.info("Deleting node.db to make room for mbtiles"); | ||||
|  |  | |||
|  | @ -61,4 +61,8 @@ public class ProgressLoggers { | |||
|       .addQueueStats(topology.inputQueue()) | ||||
|       .addThreadPoolStats(topology.name(), topology.worker()); | ||||
|   } | ||||
| 
 | ||||
|   public ProgressLoggers add(String s) { | ||||
|     return this; | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,7 @@ | |||
| package com.onthegomap.flatmap; | ||||
| 
 | ||||
| public class VectorTile { | ||||
| 
 | ||||
|   public byte[] encode() { | ||||
|   } | ||||
| } | ||||
|  | @ -1,8 +1,10 @@ | |||
| package com.onthegomap.flatmap.collections; | ||||
| 
 | ||||
| import com.onthegomap.flatmap.RenderedFeature; | ||||
| import com.onthegomap.flatmap.VectorTile; | ||||
| import com.onthegomap.flatmap.stats.Stats; | ||||
| import java.nio.file.Path; | ||||
| import java.util.Iterator; | ||||
| import java.util.function.Consumer; | ||||
| 
 | ||||
| public class MergeSortFeatureMap implements Consumer<RenderedFeature> { | ||||
|  | @ -22,4 +24,27 @@ public class MergeSortFeatureMap implements Consumer<RenderedFeature> { | |||
|   public long getStorageSize() { | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   public Iterator<TileFeatures> getAll() { | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   public static class TileFeatures { | ||||
| 
 | ||||
|     public long getNumFeatures() { | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|     public int getTileId() { | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|     public boolean hasSameContents(TileFeatures other) { | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     public VectorTile getTile() { | ||||
|       return null; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -14,6 +14,8 @@ public interface Stats { | |||
| 
 | ||||
|   void stopTimer(String name); | ||||
| 
 | ||||
|   void encodedTile(int zoom, int length); | ||||
| 
 | ||||
|   class InMemory implements Stats { | ||||
| 
 | ||||
|     private static final Logger LOGGER = LoggerFactory.getLogger(InMemory.class); | ||||
|  | @ -40,5 +42,10 @@ public interface Stats { | |||
|     public void stopTimer(String name) { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void encodedTile(int zoom, int length) { | ||||
| 
 | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ package com.onthegomap.flatmap.worker; | |||
| 
 | ||||
| import com.onthegomap.flatmap.ProgressLoggers; | ||||
| import com.onthegomap.flatmap.stats.Stats; | ||||
| import java.util.Iterator; | ||||
| import java.util.function.Consumer; | ||||
| import java.util.function.Supplier; | ||||
| 
 | ||||
|  | @ -24,6 +25,14 @@ public record Topology<T>( | |||
|     return fromGenerator(name, stats, producer, 1); | ||||
|   } | ||||
| 
 | ||||
|   public static <T> Bufferable<?, T> readFromIterator(String name, Stats stats, Iterator<T> iter) { | ||||
|     return fromGenerator(name, stats, next -> { | ||||
|       while (iter.hasNext()) { | ||||
|         next.accept(iter.next()); | ||||
|       } | ||||
|     }, 1); | ||||
|   } | ||||
| 
 | ||||
|   public static <T> Builder<?, T> readFromQueue(Stats stats, WorkQueue<T> input) { | ||||
|     return new Builder<>(input, stats); | ||||
|   } | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Mike Barry
						Mike Barry