2021-12-23 10:42:24 +00:00
|
|
|
package com.onthegomap.planetiler.examples;
|
2021-08-14 09:55:00 +00:00
|
|
|
|
2021-12-23 10:42:24 +00:00
|
|
|
import com.onthegomap.planetiler.Planetiler;
|
|
|
|
import com.onthegomap.planetiler.Profile;
|
|
|
|
import com.onthegomap.planetiler.collection.FeatureGroup;
|
|
|
|
import com.onthegomap.planetiler.collection.LongLongMap;
|
2022-03-23 00:34:54 +00:00
|
|
|
import com.onthegomap.planetiler.collection.LongLongMultimap;
|
2021-12-23 10:42:24 +00:00
|
|
|
import com.onthegomap.planetiler.config.Arguments;
|
|
|
|
import com.onthegomap.planetiler.config.MbtilesMetadata;
|
|
|
|
import com.onthegomap.planetiler.config.PlanetilerConfig;
|
|
|
|
import com.onthegomap.planetiler.mbtiles.MbtilesWriter;
|
|
|
|
import com.onthegomap.planetiler.reader.osm.OsmInputFile;
|
|
|
|
import com.onthegomap.planetiler.reader.osm.OsmReader;
|
|
|
|
import com.onthegomap.planetiler.stats.Stats;
|
|
|
|
import com.onthegomap.planetiler.util.FileUtils;
|
2021-08-17 01:51:49 +00:00
|
|
|
import java.io.IOException;
|
2021-08-14 09:55:00 +00:00
|
|
|
import java.nio.file.Files;
|
|
|
|
import java.nio.file.Path;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
/**
|
2022-03-09 02:08:03 +00:00
|
|
|
* Alternative driver program for {@link ToiletsOverlay} that uses the low-level planetiler APIs instead of the
|
|
|
|
* {@link Planetiler} convenience wrapper.
|
2021-08-14 09:55:00 +00:00
|
|
|
* <p>
|
|
|
|
* To run this example:
|
|
|
|
* <ol>
|
2022-03-09 02:08:03 +00:00
|
|
|
* <li>Download a .osm.pbf extract (see <a href="https://download.geofabrik.de/">Geofabrik download site</a></li>
|
|
|
|
* <li>then build the examples: {@code mvn clean package}</li>
|
|
|
|
* <li>then run this example:
|
|
|
|
* {@code java -cp target/*-fatjar.jar com.onthegomap.planetiler.examples.ToiletsOverlayLowLevelApi}</li>
|
|
|
|
* <li>then run the demo tileserver: {@code tileserver-gl-light --mbtiles=data/toilets.mbtiles}</li>
|
|
|
|
* <li>and view the output at <a href="http://localhost:8080">localhost:8080</a></li>
|
2021-08-14 09:55:00 +00:00
|
|
|
* </ol>
|
|
|
|
*/
|
|
|
|
public class ToiletsOverlayLowLevelApi {
|
|
|
|
|
|
|
|
private static final Logger LOGGER = LoggerFactory.getLogger(ToiletsOverlayLowLevelApi.class);
|
|
|
|
|
|
|
|
public static void main(String[] args) throws Exception {
|
2021-08-17 01:51:49 +00:00
|
|
|
run(
|
2021-09-10 00:46:20 +00:00
|
|
|
Path.of("data", "sources", "input.pbf"),
|
2021-08-17 01:51:49 +00:00
|
|
|
Path.of("data", "tmp"),
|
|
|
|
Path.of("data", "toilets.mbtiles")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void run(Path input, Path tmpDir, Path output) throws IOException {
|
2021-08-14 09:55:00 +00:00
|
|
|
// Collect runtime statistics in memory. Alternatively you can push them to
|
|
|
|
// prometheus using a push gateway (see https://github.com/prometheus/pushgateway)
|
|
|
|
Stats stats = Stats.inMemory();
|
|
|
|
Profile profile = new ToiletsOverlay();
|
|
|
|
|
2021-09-18 01:12:24 +00:00
|
|
|
// use default settings, but only allow overrides from -Dkey=value jvm arguments
|
2021-12-23 10:42:24 +00:00
|
|
|
PlanetilerConfig config = PlanetilerConfig.from(Arguments.fromJvmProperties());
|
2021-08-14 09:55:00 +00:00
|
|
|
|
2021-09-18 01:12:24 +00:00
|
|
|
// extract mbtiles metadata from profile
|
|
|
|
MbtilesMetadata mbtilesMetadata = new MbtilesMetadata(profile);
|
|
|
|
|
2021-08-14 09:55:00 +00:00
|
|
|
// overwrite output each time
|
|
|
|
FileUtils.deleteFile(output);
|
|
|
|
// make sure temp directories exist
|
|
|
|
Files.createDirectories(tmpDir);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up the FeatureGroup utility that groups features by tile. To group features by tile,
|
|
|
|
* FeatureSort first sorts them by a key that includes the tile ID in it, then FeatureGroup
|
|
|
|
* reads features in order, batching all consecutive features in the same tile together.
|
|
|
|
*
|
|
|
|
* Most applications should use external merge sort which writes features to disk, sorts
|
|
|
|
* chunks from disk in parallel, and iterates through the sorted chunks to efficiently
|
|
|
|
* sort more data than fits in memory - but if you have a lot of RAM there is FeatureSort.inMemory
|
|
|
|
* option too.
|
|
|
|
*/
|
2021-09-10 00:46:20 +00:00
|
|
|
FeatureGroup featureGroup = FeatureGroup.newDiskBackedFeatureGroup(
|
|
|
|
tmpDir.resolve("feature.db"),
|
|
|
|
profile, config, stats
|
|
|
|
);
|
2021-08-14 09:55:00 +00:00
|
|
|
|
|
|
|
try (
|
|
|
|
/*
|
|
|
|
* OSM nodes each have a latitude/longitude, and ways are a collection of node IDs so to
|
|
|
|
* get the shape of ways we need to store the latitude and longitude of each node and look
|
|
|
|
* them up when processing each way. There are several in-memory and disk-based options,
|
|
|
|
* but even for the disk-based ones you'll likely need enough RAM to fit the whole thing for
|
|
|
|
* random-access lookups to be fast.
|
|
|
|
*
|
|
|
|
* BUT, since this profile only needs nodes and not ways we can use the noop version to avoid storing
|
|
|
|
* any node locations.
|
|
|
|
*/
|
|
|
|
var nodeLocations = LongLongMap.noop();
|
2022-03-23 00:34:54 +00:00
|
|
|
var multipolygons = LongLongMultimap.noop();
|
|
|
|
var osmReader = new OsmReader("osm", new OsmInputFile(input), nodeLocations, multipolygons, profile, stats)
|
2021-08-14 09:55:00 +00:00
|
|
|
) {
|
|
|
|
// Normally you need to run OsmReader.pass1(config) first which stores node locations and preprocesses relations for
|
|
|
|
// way processing, and counts elements. But since this profile only processes nodes we can skip pass 1.
|
|
|
|
LOGGER.info("Skipping OsmReader.pass1(config) since we don't care about ways or relations");
|
|
|
|
|
|
|
|
// make the second pass through OSM data which emits output map features for each input source feature
|
|
|
|
osmReader.pass2(featureGroup, config);
|
|
|
|
} finally {
|
|
|
|
// normally you'll want to release any resources/memory held by the profile
|
|
|
|
// although in this example it's not really necessary
|
|
|
|
profile.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
// sort the features that were written to disk to prepare for grouping them into tiles
|
2021-09-10 00:46:20 +00:00
|
|
|
featureGroup.prepare();
|
2021-08-14 09:55:00 +00:00
|
|
|
|
|
|
|
// then process rendered features, grouped by tile, encoding them into binary vector tile format
|
|
|
|
// and writing to the output mbtiles file.
|
2021-09-18 01:12:24 +00:00
|
|
|
MbtilesWriter.writeOutput(featureGroup, output, mbtilesMetadata, config, stats);
|
2021-08-14 09:55:00 +00:00
|
|
|
|
|
|
|
// dump recorded timings at the end
|
|
|
|
stats.printSummary();
|
|
|
|
}
|
|
|
|
}
|