Giter Club home page Giter Club logo

planetiler's Introduction

Planetiler

Planetiler (pla·nuh·tai·lr, formerly named "Flatmap") is a tool that generates Vector Tiles from geographic data sources like OpenStreetMap. Planetiler aims to be fast and memory-efficient so that you can build a map of the world in a few hours on a single machine without any external tools or database.

Vector tiles contain raw point, line, and polygon geometries that clients like MapLibre can use to render custom maps in the browser, native apps, or on a server. Planetiler packages tiles into an MBTiles (sqlite) or PMTiles file that can be served using tools like TileServer GL or Martin or even queried directly from the browser. See awesome-vector-tiles for more projects that work with data in this format.

Planetiler works by mapping input elements to vector tile features, flattening them into a big list, then sorting by tile ID to group into tiles. See ARCHITECTURE.md for more details or this blog post for more of the backstory.

Demo

See the live demo of vector tiles created by Planetiler and hosted by the OpenStreetMap Americana Project.

Planetiler Demo Screenshot © OpenMapTiles © OpenStreetMap contributors

Usage

To generate a map of an area using the OpenMapTiles profile, you will need:

  • Java 21+ (see CONTRIBUTING.md) or Docker
  • at least 1GB of free disk space plus 5-10x the size of the .osm.pbf file
  • at least 0.5x as much free RAM as the input .osm.pbf file size

To build the map:

Using Java, download planetiler.jar from the latest release and run it:

wget https://github.com/onthegomap/planetiler/releases/latest/download/planetiler.jar
java -Xmx1g -jar planetiler.jar --download --area=monaco

Or using Docker:

docker run -e JAVA_TOOL_OPTIONS="-Xmx1g" -v "$(pwd)/data":/data ghcr.io/onthegomap/planetiler:latest --download --area=monaco

⚠️ This starts off by downloading about 1GB of data sources required by the OpenMapTiles profile including ~750MB for ocean polygons and ~240MB for Natural Earth Data.

To download smaller extracts just for Monaco:

Java:

java -Xmx1g -jar planetiler.jar --download --area=monaco \
  --water-polygons-url=https://github.com/onthegomap/planetiler/raw/main/planetiler-core/src/test/resources/water-polygons-split-3857.zip \
  --natural-earth-url=https://github.com/onthegomap/planetiler/raw/main/planetiler-core/src/test/resources/natural_earth_vector.sqlite.zip

Docker:

docker run -e JAVA_TOOL_OPTIONS="-Xmx1g" -v "$(pwd)/data":/data ghcr.io/onthegomap/planetiler:latest --download --area=monaco \
  --water-polygons-url=https://github.com/onthegomap/planetiler/raw/main/planetiler-core/src/test/resources/water-polygons-split-3857.zip \
  --natural-earth-url=https://github.com/onthegomap/planetiler/raw/main/planetiler-core/src/test/resources/natural_earth_vector.sqlite.zip

You will need the full data sources to run anywhere besides Monaco.

To view tiles locally:

Using Node.js:

npm install -g tileserver-gl-light
tileserver-gl-light data/output.mbtiles

Or using Docker:

docker run --rm -it -v "$(pwd)/data":/data -p 8080:8080 maptiler/tileserver-gl -p 8080

Then open http://localhost:8080 to view tiles.

Some common arguments:

  • --output tells planetiler where to write output to, and what format to write it in. For example --output=australia.pmtiles creates a pmtiles archive named australia.pmtiles.
  • --download downloads input sources automatically and --only-download exits after downloading
  • --area=monaco downloads a .osm.pbf extract from Geofabrik
  • --osm-path=path/to/file.osm.pbf points Planetiler at an existing OSM extract on disk
  • -Xmx1g controls how much RAM to give the JVM (recommended: 0.5x the input .osm.pbf file size to leave room for memory-mapped files)
  • --force overwrites the output file
  • --help shows all of the options and exits

Git submodules

Planetiler has a submodule dependency on planetiler-openmaptiles. Add --recurse-submodules to git clone, git pull, or git checkout commands to also update submodule dependencies.

To clone the repo with submodules:

git clone --recurse-submodules https://github.com/onthegomap/planetiler.git

If you already pulled the repo, you can initialize submodules with:

git submodule update --init

To force git to always update submodules (recommended), run this command in your local repo:

git config --local submodule.recurse true

Learn more about working with submodules here.

Generating a Map of the World

See PLANET.md.

Generating Custom Vector Tiles

If you want to customize the OpenMapTiles schema or generate an mbtiles file with OpenMapTiles + extra layers, then fork https://github.com/openmaptiles/planetiler-openmaptiles make changes there, and run directly from that repo. It is a standalone Java project with a dependency on Planetiler.

If you want to generate a separate mbtiles file with overlay layers or a full custom basemap, then:

  • For simple schemas, run a recent planetiler jar or docker image with a custom schema defined in a yaml configuration file. See planetiler-custommap for details.
  • For complex schemas (or if you prefer working in Java), create a new Java project that depends on Planetiler. See the planetiler-examples project for a working example.

If you want to customize how planetiler works internally, then fork this project, build from source, and consider contributing your change back for others to use!

Benchmarks

Some example runtimes for the OpenMapTiles profile (excluding downloading resources):

Input Version Machine Time output size Logs
s3://osm-pds/2024/planet-240115.osm.pbf (69GB) 0.7.0 c3d-standard-180 (180cpu/720GB) 22m cpu:44h34m avg:120 69GB pmtiles logs
s3://osm-pds/2024/planet-240108.osm.pbf (73GB) 0.7.0 c7gd.16xlarge (64cpu/128GB) 42m cpu:42m28s avg:52 69GB pmtiles logs
s3://osm-pds/2022/planet-220530.osm.pbf (69GB) 0.5.0 c6gd.16xlarge (64cpu/128GB) 53m cpu:41h58m avg:47.1 79GB mbtiles logs, VisualVM Profile
s3://osm-pds/2022/planet-220530.osm.pbf (69GB) 0.5.0 c6gd.8xlarge (32cpu/64GB) 1h27m cpu:37h55m avg:26.1 79GB mbtiles logs
s3://osm-pds/2022/planet-220530.osm.pbf (69GB) 0.5.0 c6gd.4xlarge (16cpu/32GB) 2h38m cpu:34h3m avg:12.9 79GB mbtiles logs

Merging nearby buildings at z13 is very expensive, when run with --building-merge-z13=false:

Input Version Machine Time output size Logs
s3://osm-pds/2024/planet-240115.osm.pbf (69GB) 0.7.0 c3d-standard-180 (180cpu/720GB) 16m cpu:27h45m avg:104 69GB pmtiles logs
s3://osm-pds/2024/planet-240108.osm.pbf (73GB) 0.7.0 c7gd.16xlarge (64cpu/128GB) 29m cpu:23h57 avg:50 69GB pmtiles logs
s3://osm-pds/2024/planet-240108.osm.pbf (73GB) 0.7.0 c7gd.2xlarge (8cpu/16GB) 3h35m cpu:19h45 avg:5.5 69GB pmtiles logs
s3://osm-pds/2024/planet-240108.osm.pbf (73GB) 0.7.0 im4gn.large (2cpu/8GB) 18h18m cpu:28h6m avg:1.5 69GB pmtiles logs
s3://osm-pds/2022/planet-220530.osm.pbf (69GB) 0.5.0 c6gd.16xlarge (64cpu/128GB) 39m cpu:27h4m avg:42.1 79GB mbtiles logs, VisualVM Profile

Alternatives

Some other tools that generate vector tiles from OpenStreetMap data:

  • OpenMapTiles is the reference implementation of the OpenMapTiles schema that the OpenMapTiles profile is based on. It uses an intermediate postgres database and operates in two modes:
    1. Import data into database (~1 day) then serve vector tiles directly from the database. Tile serving is slower and requires bigger machines, but lets you easily incorporate realtime updates
    2. Import data into database (~1 day) then pregenerate every tile for the planet into an mbtiles file which takes over 100 days or a cluster of machines, but then tiles can be served faster on smaller machines
  • Tilemaker uses a similar approach to Planetiler (no intermediate database), is more mature, and has a convenient lua API for building custom profiles without recompiling the tool, but takes about a day to generate a map of the world

Some companies that generate and host tiles for you:

If you want to host tiles yourself but have someone else generate them for you, those companies also offer plans to download regularly-updated tilesets.

Features

  • Supports Natural Earth, OpenStreetMap .osm.pbf, geopackage, and Esri Shapefiles data sources
  • Writes to MBTiles or or PMTiles output.
  • Java-based Profile API to customize how source elements map to vector tile features, and post-process generated tiles using JTS geometry utilities
  • YAML config file format that lets you create custom schemas without writing Java code
  • Merge nearby lines or polygons with the same tags before emitting vector tiles
  • Automatically fixes self-intersecting polygons
  • Built-in OpenMapTiles profile based on OpenMapTiles v3.13.1
  • Optionally download additional name translations for elements from Wikidata
  • Export real-time stats to a prometheus push gateway using --pushgateway=http://user:password@ip argument (and a grafana dashboard for viewing)
  • Automatically downloads region extracts from Geofabrik using geofabrik:australia shortcut as a source URL
  • Unit-test profiles to verify mapping logic, or integration-test to verify the actual contents of a generated mbtiles file (example)

Limitations

  • It is harder to join and group data than when using database. Planetiler automatically groups features into tiles, so you can easily post-process nearby features in the same tile before emitting, but if you want to group or join across features in different tiles, then you must explicitly store data when processing a feature to use with later features or store features and defer processing until an input source is finished (boundary layer example)
  • Planetiler only does full imports from .osm.pbf snapshots, there is no way to incorporate real-time updates.

Use as a library

Planetiler can be used as a maven-style dependency in a Java project using the settings below:

Maven

Add this repository block to your pom.xml:

<repositories>
  <repository>
    <id>osgeo</id>
    <name>OSGeo Release Repository</name>
    <url>https://repo.osgeo.org/repository/release/</url>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
    <releases>
      <enabled>true</enabled>
    </releases>
  </repository>
</repositories>

Then add the following dependency:

<dependency>
  <groupId>com.onthegomap.planetiler</groupId>
  <artifactId>planetiler-core</artifactId>
  <version>${planetiler.version}</version>
</dependency>

Gradle

Set up your repositories block::

mavenCentral()
maven {
    url "https://repo.osgeo.org/repository/release/"
}

Set up your dependencies block:

implementation 'com.onthegomap.planetiler:planetiler-core:<version>'

Contributing

Pull requests are welcome! See CONTRIBUTING.md for details.

Support

For general questions, check out the #planetiler channel on OSM-US Slack (get an invite here), or start a GitHub discussion.

Found a bug or have a feature request? Open a GitHub issue to report.

This is a side project, so support is limited. If you have the time and ability, feel free to open a pull request to fix issues or implement new features.

Acknowledgement

Planetiler is made possible by these awesome open source projects:

See NOTICE.md for a full list and license details.

Author

Planetiler was created by Michael Barry for future use generating custom basemaps or overlays for On The Go Map.

License and Attribution

Planetiler source code is licensed under the Apache 2.0 License, so it can be used and modified in commercial or other open source projects according to the license guidelines.

Maps built using planetiler do not require any special attribution, but the data or schema used might. Any maps generated from OpenStreetMap data must visibly credit OpenStreetMap contributors. Any map generated with the profile based on OpenMapTiles or a derivative must visibly credit OpenMapTiles as well.

planetiler's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

planetiler's Issues

[FEATURE] parallel tile generation and road network connectivity

Hi, thanks for creating this - it could be a good match to other map tooling I'm developing including a tile archive format and canvas renderer.

One thing I noticed with whipping up a quick example is that the basemap result for motorway network has gaps in it - see attached screenshot. The root cause for the gaps is that OSM ways that connect two other high-importance ways - like highway=motorway, assigned to appear at a lower zoom level like z9 might actually be tagged at a lower level like highway=primary and not be included in z9. This is because OSM tags are based on physical features and not cartographic importance.

The approach I usually take to solve this is to generalize roads via a new tag class outside of the OSM tagging conventions based on connectivity to other ways. This would break the parallel design described in ARCHITECTURE.md because feature generation at the early stage could not proceed independently per-feature. I also don't think it could fit into the advanced joining/grouping in README#Limitations because the late-stage, pre-write processing of features at the tile level would not have access to those missing ways.

Is this mode of processing something you would consider in scope for Planetiler, if it necessitates changing the tile generation strategy? There may be ways to accommodate it into the existing design if candidate ways were saved out similar to boundary relations but the quantity of candidates would be very large.
Screen Shot 2022-01-14 at 12 21 29 PM

[BUG] Z4 boundaries from OSM should not include adm0_l/admin0_r

Describe the bug
adm0_{l,r} tags show up on regular boundaries at z5 but the demo shows them at z4 on maritime boundaries derived from OSM data and not natural earth.

To Reproduce
Steps to reproduce the behavior:

  1. Generate a world map with basemap profile including Z4
  2. Inspect the generated tiles

Expected behavior
Boundary lines have adm0_{l,r} tags starting zt z5, not z4

Screenshots
image

Environment (please complete the following information):
n/a

Additional context
n/a

[BUG] At zoom >= 5 I see nothing

Describe the bug
At zoom level at and above 5 I see no features.

To Reproduce

  1. Visit https://onthegomap.github.io/flatmap-demo/#5/40.75/-108.36

Expected behavior
I see something similar to what I see at https://onthegomap.github.io/flatmap-demo/#4.9/40.75/-108.36

Screenshots
This is what I see when I follow the to reproduce steps:

Screenshot_20211025-211245

Environment (please complete the following information):

  • Hardware: Moto One 5G Ace
  • OS: Android 10 (build QZKS30.Q4-40-95-2)
  • Java version and distribution: n/a
  • Maven version: n/a

Additional context
I can reproduce in mobile Firefox and mobile Chrome. I haven't tested anything else.

[BUG] 302 download responses are not followed

Describe the bug

When downloading area .osm.pbf files, a 302 redirect is not followed, instead, an exception is raised.

To Reproduce

java -Xmx1g -jar flatmap.jar --download --area=germany

Stack trace

``` Exception in thread "main" java.lang.IllegalStateException: Error getting size of https://download.geofabrik.de/europe/germany-latest.osm.pbf at com.onthegomap.flatmap.util.Downloader.run(Downloader.java:178) at com.onthegomap.flatmap.FlatmapRunner.download(FlatmapRunner.java:574) at com.onthegomap.flatmap.FlatmapRunner.run(FlatmapRunner.java:475) at com.onthegomap.flatmap.basemap.BasemapMain.run(BasemapMain.java:50) at com.onthegomap.flatmap.basemap.BasemapMain.main(BasemapMain.java:14) at com.onthegomap.flatmap.Main.main(Main.java:50) Caused by: java.util.concurrent.ExecutionException: java.lang.IllegalStateException: Bad response: 302 at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396) at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2096) at com.onthegomap.flatmap.util.Downloader.run(Downloader.java:175) ... 5 more Caused by: java.lang.IllegalStateException: Bad response: 302 at com.onthegomap.flatmap.util.Downloader.assertOK(Downloader.java:94) at com.onthegomap.flatmap.util.Downloader.lambda$httpHead$7(Downloader.java:232) at java.net.http/jdk.internal.net.http.Http1Exchange.readBodyAsync(Http1Exchange.java:373) at java.net.http/jdk.internal.net.http.Exchange.readBodyAsync(Exchange.java:185) at java.net.http/jdk.internal.net.http.MultiExchange.lambda$responseAsync0$4(MultiExchange.java:353) at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1150) at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) at java.base/java.util.concurrent.CompletableFuture.postFire(CompletableFuture.java:614) at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:653) at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:482) at java.net.http/jdk.internal.net.http.HttpClientImpl$DelegatingExecutor.execute(HttpClientImpl.java:157) at java.base/java.util.concurrent.CompletableFuture$UniCompletion.claim(CompletableFuture.java:572) at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:642) at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147) at java.net.http/jdk.internal.net.http.Http1Response$HeadersReader.handle(Http1Response.java:695) at java.net.http/jdk.internal.net.http.Http1Response$HeadersReader.handle(Http1Response.java:621) at java.net.http/jdk.internal.net.http.Http1Response$Receiver.accept(Http1Response.java:612) at java.net.http/jdk.internal.net.http.Http1Response$HeadersReader.tryAsyncReceive(Http1Response.java:668) at java.net.http/jdk.internal.net.http.Http1AsyncReceiver.flush(Http1AsyncReceiver.java:233) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$LockingRestartableTask.run(SequentialScheduler.java:205) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:149) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:230) at java.net.http/jdk.internal.net.http.HttpClientImpl$DelegatingExecutor.execute(HttpClientImpl.java:157) at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:305) at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:274) at java.net.http/jdk.internal.net.http.Http1AsyncReceiver.asyncReceive(Http1AsyncReceiver.java:464) at java.net.http/jdk.internal.net.http.Http1AsyncReceiver$Http1TubeSubscriber.onNext(Http1AsyncReceiver.java:584) at java.net.http/jdk.internal.net.http.Http1AsyncReceiver$Http1TubeSubscriber.onNext(Http1AsyncReceiver.java:541) at java.net.http/jdk.internal.net.http.common.SSLTube$DelegateWrapper.onNext(SSLTube.java:210) at java.net.http/jdk.internal.net.http.common.SSLTube$SSLSubscriberWrapper.onNext(SSLTube.java:492) at java.net.http/jdk.internal.net.http.common.SSLTube$SSLSubscriberWrapper.onNext(SSLTube.java:295) at java.net.http/jdk.internal.net.http.common.SubscriberWrapper$DownstreamPusher.run1(SubscriberWrapper.java:316) at java.net.http/jdk.internal.net.http.common.SubscriberWrapper$DownstreamPusher.run(SubscriberWrapper.java:259) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$LockingRestartableTask.run(SequentialScheduler.java:205) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:149) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:230) at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:303) at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:256) at java.net.http/jdk.internal.net.http.common.SubscriberWrapper.outgoing(SubscriberWrapper.java:232) at java.net.http/jdk.internal.net.http.common.SubscriberWrapper.outgoing(SubscriberWrapper.java:198) at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate$Reader.processData(SSLFlowDelegate.java:444) at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate$Reader$ReaderDownstreamPusher.run(SSLFlowDelegate.java:268) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$LockingRestartableTask.run(SequentialScheduler.java:205) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:149) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:230) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833) ```

Expected behavior

The 302 redirect should be followed and the download should succeed.

Environment (please complete the following information):

Linux hostname 5.15.5-arch1-1 #1 SMP PREEMPT Thu, 25 Nov 2021 22:09:33 +0000 x86_64 GNU/Linux
openjdk version "17.0.1" 2021-10-19
OpenJDK Runtime Environment (build 17.0.1+12)
OpenJDK 64-Bit Server VM (build 17.0.1+12, mixed mode)

Additional context

As you can see, download.geofabrik.de returns a 302 redirect:

$ curl -v https://download.geofabrik.de/europe/germany-latest.osm.pbf 2>&1 | grep -E '< HTTP|Location'
< HTTP/1.1 302 Found
< Location: http://ftp5.gwdg.de/pub/misc/openstreetmap/download.geofabrik.de/germany-latest.osm.pbf

[FEATURE] Parallel chunk writing in OSM pass2

When running planetiler on a machine with many cores, OSM pass2 ends up limited by having a single thread writing feature chunk files:

image

In order to better utilize system resources on machines with lots of cores, this writing could be done by parallel threads (maybe 1 writer per 32 workers or so).

[BUG] Missing route_N attributes for some route relations

Route relations with long network values are not getting rendered by planetiler. Examples:

New Jersey Turnpike:
https://www.openstreetmap.org/relation/189809 network=US:NJ:NJTP ref=NJTP
Atlantic City Expressway:
https://www.openstreetmap.org/relation/189490 network=US:NJ:NJTP ref=NJTP
Garden State Parkway:
https://www.openstreetmap.org/relation/184099 network=US:NJ:GSP ref=GSP
US-30 Alternate Truck Business:
https://www.openstreetmap.org/relation/6849001 network=US:US:Alternate:Truck:Business ref=30
PA Turnpike
https://www.openstreetmap.org/relation/3075582 network=US:PA:Turnpike ref=PATP
New Jersey CR 539
https://www.openstreetmap.org/relation/549770 network=US:NJ:CR ref=539

Openstreetmap-americana rendering of NJ turnpike: https://zelonewolf.github.io/openstreetmap-americana/#11/40.2578/-74.4618

Tileserver output showing only I-95 and not NJTP:
image

To Reproduce
Steps to reproduce the behavior:

  1. `docker run -e JAVA_TOOL_OPTIONS="-Xmx5g" -v "$(pwd)/data":/data ghcr.io/onthegomap/planetiler:latest --download --area=us
  2. Run mbtiles file in tileserver-gl
  3. Observe missing route_N values from the route relation members above.

Expected behavior
Listed route relations show be present on member ways in the tile server. For example, along the NJ turnpike, I expect to see route_1=US:I=95 + route_2=US:NJ:NTJP=NTJP.

Screenshots
Side by side openstreetmap-americana renderings of MapTiler Cloud vs planetiler:
image
image

Environment

  • Hardware: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz, 32Gb Ram, 1TB SSD
  • OS: Ubuntu 21.04
  • Java version and distribution: Java(TM) SE Runtime Environment (build 17.0.1+12-LTS-39)
  • Maven version: None

[BUG] Download error when regenerating OpenMapTiles

Describe the bug
On Windows 10, when generating using scripts/regenerate-openmaptiles, an error is thrown during the download of omt yaml files.

Exception in thread "main" java.io.FileNotFoundException: https://raw.githubusercontent.com/openmaptiles/openmaptiles/v3.12.2/layers\water\mapping.yaml

image
Pasting the suspect URL into Chrome works fine. Turns out that accessing this URL through Java returns a 404 for this particular .yaml file.

This bug results from the forward-slash and backslash in the URL (probably due to windows file separator).

To fix this, I added url = url.replaceAll("\\\\", "/"); above line 108 of Generate.java .

https://github.com/lokkelvin2/planetiler/blob/0214605799655c28f0a33a6714ebb0b19eaf38da/planetiler-basemap/src/main/java/com/onthegomap/planetiler/basemap/Generate.java#L108

Note that I have not tested the impact of this patch on non-windows machines.

[BUG] NPEs while generating planet

While generating the planet, there were a few NPEs:

0:33:28 ERR [osm_pass2:process] - Error processing OSM way 121137742
java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Map.get(Object)" is null
	at com.onthegomap.planetiler.basemap.layers.Transportation.getMinzoom(Transportation.java:424)
	at com.onthegomap.planetiler.basemap.layers.Transportation.process(Transportation.java:362)
	at com.onthegomap.planetiler.basemap.BasemapProfile.lambda$new$6(BasemapProfile.java:134)
	at com.onthegomap.planetiler.ForwardingProfile.processFeature(ForwardingProfile.java:116)
	at com.onthegomap.planetiler.reader.osm.OsmReader.lambda$pass2$2(OsmReader.java:279)
	at com.onthegomap.planetiler.worker.WorkerPipeline$Builder.lambda$addWorker$0(WorkerPipeline.java:246)
	at com.onthegomap.planetiler.worker.Worker.lambda$new$0(Worker.java:49)
	at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.base/java.lang.Thread.run(Unknown Source)
0:38:40 ERR [osm_pass2:process] - Error processing OSM way 283144232
java.lang.NullPointerException
0:51:06 ERR [osm_pass2:process] - Error processing OSM way 712454442
java.lang.NullPointerException

[BUG] Synchronize less in `transportation_name` layer

This block in the transportation name layer does too much work inside a synchronized block, which holds OSM pass 1 way processing back from saturating CPU cores:

synchronized (motorwayJunctionHighwayClasses) {
for (int i = 0; i < nodes.size(); i++) {
long node = nodes.get(i);
if (motorwayJunctionHighwayClasses.containsKey(node)) {
byte oldValue = motorwayJunctionHighwayClasses.get(node);
byte newValue = cls.value;
if (newValue > oldValue) {
motorwayJunctionHighwayClasses.put(node, newValue);
}
}
}

image

Different name?

The main feedback on https://news.ycombinator.com/item?id=28986762 was that "flatmap" is ambiguous and not unique. Before publishing to maven central, package managers, etc should decide whether or not to keep "flatmap" or use something different.

Pros:

  • easier to find through search.
  • It's still early so there are too many inbound links yet

Cons:

  • there are still some links, forks, and stars so need to be careful to preserve those

Any suggestions?

[FEATURE] Customization of OpenMapTiles

Is your feature request related to a problem? Please describe.
Problem 1: License. The license of OpenMapTiles is confusing me. I am never sure if I can use OpenMapTiles for a commercial project. I don't know if I have to give attribution to OpenMapTiles if I use for example only a single layer from OpenMapTiles like --only_layers=transportation.

Problem 2: Customization. OpenMapTiles is a great start to make a map. But I don't need all the information it provides (e.g. landcover farmland). And other information is missing (e.g. powerlines). I don't know what is the best way to do this. Fork and edit the base profile?

Describe the solution you'd like
I would like to make a map from ground up where I say I would like to have roads, houses, residential area, forest, water, place names. The building blocks could still use the logic that is already implemented in the base profile.

Describe alternatives you've considered
My current approach would be to comment out all the things I do not need in the base profile and add new layers with my custom information.

Additional context
Discussion #81 is probably related to this issue.

Since the resulting tiles are not compliant with the OpenMapTiles schema, I would like to remove the attribution altogether. I don't know if this is unfair? It just feels wrong to keep linking to OpenMapTiles if the technology used for the map tiles is a different one...

[FEATURE] Parallel temp feature reads

During the mbtiles write phase, we read temporary features from disk and do a k-way merge to group features into tiles. This single-threaded bottleneck prevents us from saturating CPUs on larger machines:

image

To speed this up, optionally support 2 parallel read threads, and a thread that merges the results.

Adding building names to basemap profile

Describe the bug
The names of POI/buildings are missing using the default basemap profile.

Expected behavior
The output mbtiles should include the name tags of buildings and POIs but they are dropped.

To Reproduce

  1. Download Malaysia, Singapore, and Brunei from geofabrik
  2. Run java -Xmx1g -jar planetiler.jar --download --osm_path="malaysia-singapore-brunei-old.osm.pbf"
  3. Inspect location lat: 1.29788, lon: 103.77677

Long description
I am generating vector tiles for Singapore and have been using tilemaker prior to planetiler. Using Way 427077072 as an example, the building name in OSM is 'Ridge View Tower' and I would expect the output mbtiles to contain the same information.

In the planetiler mbtiles, however, this name field is missing. Inspecting the planetiler mbtiles using QGIS reveals that planetiler only saves housenumbers and does not save POI/building names.

Here are some screenshots describing the problem:

OSM groundtruth:
osm1
Planetiler output:
planetiler1
Tilemaker output:
tilemaker1

Is there a way I can edit the planetiler profile to match the detailed output of tilemaker/OSM ?

Environment (please complete the following information):

  • OS: Windows 10
  • Java version and distribution: [e.g. Eclipse Temurin 17.0.2]

[FEATURE] Include OSM replication timestamp in mbtiles metadata

It would be helpful if the tilejson output (which typically copies all key/value pairs from the mbtiles metadata table) included the timestamp/version of input source data to help you understand what you're seeing in the output. To do this let's add planetiler:osm:timestamp metadata attribute that copies the OSM replication timestamp to output file.

Alternatives Considered

Include the input data source version/timestamp in description or version field. This stays within the tilejson/mbtiles spec, but is harder for clients to parse. Mbtiles servers seem to just pass any unknown fields through from metadata to tilejson, so custom keys seem like a better option.

[BUG] Retry failed wikidata download

Describe the bug
If wikidata names fail to download, the download exits with a stack trace such as:

Exception in thread "main" java.lang.IllegalStateException: java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.net.http.HttpTimeoutException: request 
timed out
at com.onthegomap.planetiler.stats.ProgressLoggers.await(ProgressLoggers.java:382)
at com.onthegomap.planetiler.stats.ProgressLoggers.awaitAndLog(ProgressLoggers.java:370)
at com.onthegomap.planetiler.worker.WorkerPipeline.awaitAndLog(WorkerPipeline.java:58)
at com.onthegomap.planetiler.util.Wikidata.fetch(Wikidata.java:152)
at com.onthegomap.planetiler.Planetiler.run(Planetiler.java:487)
at com.onthegomap.planetiler.basemap.BasemapMain.run(BasemapMain.java:50)
at com.onthegomap.planetiler.basemap.BasemapMain.main(BasemapMain.java:14)
at com.onthegomap.planetiler.Main.main(Main.java:50)
Caused by: java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.net.http.HttpTimeoutException: request timed out
at java.base/java.util.concurrent.CompletableFuture.reportGet(Unknown Source)
at java.base/java.util.concurrent.CompletableFuture.get(Unknown Source)
at com.onthegomap.planetiler.stats.ProgressLoggers.await(ProgressLoggers.java:379)
... 7 more
Caused by: java.lang.RuntimeException: java.net.http.HttpTimeoutException: request timed out
at com.onthegomap.planetiler.util.Wikidata.flush(Wikidata.java:254)
at com.onthegomap.planetiler.util.Wikidata.fetch(Wikidata.java:266)
at com.onthegomap.planetiler.util.Wikidata.lambda$fetch$1(Wikidata.java:134)
at com.onthegomap.planetiler.worker.WorkerPipeline$Builder.lambda$sinkTo$2(WorkerPipeline.java:268)
at com.onthegomap.planetiler.worker.Worker.lambda$new$0(Worker.java:50)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.net.http.HttpTimeoutException: request timed out
at java.net.http/jdk.internal.net.http.HttpClientImpl.send(Unknown Source)
at java.net.http/jdk.internal.net.http.HttpClientFacade.send(Unknown Source)
at com.onthegomap.planetiler.util.Wikidata$Client.lambda$wrap$0(Wikidata.java:328)
at com.onthegomap.planetiler.util.Wikidata.queryWikidata(Wikidata.java:293)
at com.onthegomap.planetiler.util.Wikidata.flush(Wikidata.java:249)
... 8 more

Instead, this download should be retried.

To Reproduce
Happens randomly when using --fetch-wikidata options.

Expected behavior
Failed wikidata downloads are retried

Environment (please complete the following information):

  • AWS r6g.16xlarge
  • Ubuntu 20.04

Additional context
Full command:

sudo docker run -e JAVA_TOOL_OPTIONS='-Xmx80g' -v "$(pwd)/data":/data \
  ghcr.io/onthegomap/planetiler:latest --area=planet --bounds=world --download --download-threads=10 --download-chunk-size-mb=1000 \
  --only-fetch-wikidata

[FEATURE] Get flatmap-core into Maven Central

Is your feature request related to a problem? Please describe.
Maven support in GitHub packages is flaky and does not allow anonymous access.

Describe the solution you'd like
Get flatmap-core into Maven Central so it can be installed without changing your .m2/settings.xml file.

Describe alternatives you've considered
A read-only personal access token included in the repo - github deletes it automatically.

Additional context
n/a

Customization in Java / Examples

I would like to provide a customization example in Java. I made a powerlines map here https://github.com/wipfli/powerlines-switzerland and was wondering if we could add it or link it to planetiler?

For users, I think it would be nice to see how to use planetiler as a dependency. Having a separate example project might be useful for this. The powerlines example above has to be adjusted I think.

One thing I found useful when starting with Mapbox GL JS was their collection of examples https://docs.mapbox.com/mapbox-gl-js/example/. These examples have a title, a 3-sentence text, and like 20 lines of code. Maybe we could make something similar where we highlight how to use different features of Planetiler.

[BUG] OMT Basemap generates transportation_name entry for minor roads

Describe the bug

Planetiler creates a transportation_name entry with a ref for minor roads. This differs to OMT. I have a style that shows road signs. It now shows road signs for hiking and cycling routes.

To Reproduce
Steps to reproduce the behavior:

  1. Compare OMT tiles to Planetiler OMT.

For example:
https://www.openstreetmap.org/relation/2268453
https://www.openstreetmap.org/relation/1153402

Expected behavior

I don't think it's an issue that Planetiler does this. There are applications that want to show highway signs for cycle routes etc. At least I think we should document it. That way, I know what I am getting and can update my styles to consider this change.

Screenshots

OMT vs Planetiler:
Screenshot 2022-03-23 at 08 45 57
Screenshot 2022-03-23 at 08 46 13

[FEATURE] Add utility to abbreviate road names

When implementing the basemap layer, I did not port road name abbreviations from https://github.com/giggls/mapnik-german-l10n because of the licensing and just pass road names from OpenStreetMap directly. This is not ideal because clients like MapLibre won't show labels on a line if we can't fit the entire string, so overall shorter label names will increase label density.

I think it would be best to abbreviate all road names (not just long ones), for example:

Input Output
Park Avenue Park Ave
Northeast Boulevard NE Blvd
East 61st Street E 61st St
First Street 1st St
South Park Street S Park St
South Street South St

Some possible data sources:

[FEATURE] OSM change file handling

We've been using pyosmium-up-to-date to catch a planet.osm.pbf file up to date with changes to OSM. That process takes about 1 minute per day of updates to download plus 40 minutes to rewrite planet.osm.pbf - almost as long as rendering all tiles for the planet.

In order to produce live planet.mbtiles as quickly as possible, planetiler should at least be able to read OSM change files as input and apply them to the PBF file being read. Even better would be if it could automatically download the necessary change files to bring an input planet up-to-date without external dependencies.

[FEATURE] Polygon centerlines

Currently the basemap profile uses lake centerlines from the unmaintained https://github.com/lukasmartinelli/osm-lakelines repo. It would be nice if flatmap could generate centerlines for polygons itself out of the box. In most cases you would probably want to fall back to a point label if the polygon is not elongated. It might also make sense to limit minzoom based on the length of the line or area of the polygon if it's a point so the entire text fits into the polygon.

Remove geotools dependency for reading shapefiles

Geotools is not in maven central which adds an extra step for people to build the project, and the licensing is not great. Geotools is really only needed to read shapefiles (including coordinate system transformation) which there should be another option for.

Apache SIS looks promising.

[FEATURE] Add linting

To improve consistency between people who may use different editors, we should adopt a java linter like checkstyle or sonarlint. You should be able to run it from the command line, through plugins to popular editors, and a github action should highlight any issues as comments on a PR.

[BUG] Limit latin name extraction to valid language codes with no non-latin characters

The most robust fix would be to limit the subkeys to those that would be valid BCP 47 codes, like xx and xx-YY and xx-YY-ZZZZ. But limiting it to the languages in the profile should work too.

I think the revised non-Latin detection code would still be worth pursuing regardless. With just the smaller fix you’re suggesting, there will be cases where an alternative language’s name is arbitrarily chosen just because of a “non-Latin” character.

Originally posted by @1ec5 in #86 (comment)

[FEATURE] Fail fast when running planetiler with insufficient memory/storage

Is your feature request related to a problem? Please describe.
If a planetiler render is launched with insufficient memory or disk space, the build will run until memory/disk is exhausted. However, this could be an hour or more before the limit is encountered, resulting in wasted time and an unclear error message to users (typically some type of out of memory error).

Describe the solution you'd like
Planetiler should note the size of the input file, and if it calculates that memory or disk space is insufficient to run to completion, it should fail quickly with an error message indicating the need for more disk space or memory.

[BUG] Highways and expressways (in Poland) have wrong `ref`

Describe the bug
I noticed that highways and expressways in Poland have the wrong ref. Right now, they are using the ref value of the International road network (network = "e-road"). This is an example relation https://www.openstreetmap.org/relation/33702 from e-road network. And this is a relation that should be actually used for ref https://www.openstreetmap.org/relation/112778

It looks that the problem only happens for polish roads. For example, highways in Germany have correct local refs.

To Reproduce
Steps to reproduce the behavior:

  1. Download data from https://download.geofabrik.de/europe/poland/pomorskie.html
  2. Run command java -jar planetiler-dist/target/*with-deps.jar --force=true --osm-path=data/sources/pomorskie-latest.osm.pbf
  3. See error

Expected behavior

Relations that are part of network="e-road shouldn't be used for getting ref for transportation_name layer. Maybe

Screenshots

Planetiler:
Screenshot 2022-03-23 at 10 31 08

OMT:
Screenshot 2022-03-23 at 10 31 28

Name translation improvements

LanguageUtils is a straight port from openmaptiles logic, but there are a few issues with it. Please add a comment with any suggestions for improving the logic to assign element names, picking latin/nonlatin names, transliterating, etc. along with some example test cases to illustrate the desired behavior.

[FEATURE] Built-in Natural Earth profile

It would be cool to include a profile showcasing all of the vector layers available in Natural Earth

Some issues I ran into prototyping this:

  • Need to use Natural Earth shapefile instead of sqlite (and deprecate sqlite one since it's redundant) since some data only exists in the shapefile distribution (i.e. bathymetry)
  • Shapefile reader only supports a single .shp file inside a zip, but natural earth is distributed as many .shp files in a single zip file. There's some debug data in there too so need a way to filter to only some .shp files.
  • Shapefile reader needs to support configurable charsets (Natural Earth uses UTF-8)
  • Some named polygons (i.e. Physical Labels) are useless in MapLibre, they need to be converted to centerlines (#13) or centroid labels to be useful
  • Visvalingham-Wyatt simplification would produce better results simplifying geometries at lower zoom levels

[FEATURE] Limit download bandwidth

Occasionally, when downloading resources on a digitalocean droplet, the download triggers a "black hole" condition where they think there's a denial of service attack underway against your droplet. To fix this, we should add an option to limit inbound bandwidth on the downloader.

[FEATURE] Real-time OpenStreetMap updates?

Is your feature request related to a problem? Please describe.
Planetiler was initially designed to work in batch mode but it might be possible to get incremental minutely updates from OpenStreetMap.

Describe the solution you'd like
Run planetiler once to get a base tileset plus some extra indices, then run a continuous (or cron) process to crawl the latest OSM replication diffs (https://wiki.openstreetmap.org/wiki/Planet.osm/diffs) and apply them to the tileset. The initial run could be slower than batch mode, but should still be reasonable (<12 hours) and incremental updates should be <1 minute. Ideally, incremental updates should need much less RAM than a full import.

Describe alternatives you've considered
Start from a planet.osm.pbf dump, then loop continuously:

  • download and apply all diff files to bring the planet.osm.pbf up to date
  • then run planetiler to generate a new planet.mbtiles files
  • then swap out the file that you are serving from

This would result in a 1-3 hour latency, depending on how big of a machine you use.

Open Questions

  • Should the process update a local mbtiles file so each shard serving tiles would have an update process running? Or should it keep an external data store (like Postgres, or a k/v store) updated?
  • Is there an API that can provide info for all of the nodes/ways/relations that need to be re-rendered when an related element changes (I.e. a node moves so we need to re-render ways that contain it)? Otherwise we'll need to store a full mirror of all the relevant raw data from osm.

[FEATURE] config-based profiles

Right now you need to write Java code to build a custom profile. It might be nice if you could also write a json or yaml file that defines the logic and config for the profile.

[BUG] data missing for quickstart

Describe the bug

The quickstart-from-source.sh script does not download data.

To Reproduce
Steps to reproduce the behavior:

  1. clone this repo
  2. configure java and intellij according to contributing guidelines
  3. run ./quickstart-from-source.sh
  4. Error Exception in thread "main" java.lang.IllegalArgumentException: data/sources/lake_centerline.shp.zip does not exist

Expected behavior
quickstart-from-souce.sh should download the required assets.

Environment (please complete the following information):

  • Hardware: dell xps 2021
  • OS: ubuntu
  • Java version and distribution: java 17.0.1 2021-10-19 LTS

[BUG] TransportationName: calculate rank doesn't handle major roads that are not part of a preconfigured network

Describe the bug

In Germany Planetiler is generating only few refs for major roads like motorways or trunks. The reason seems to be that Planetiler calculates the rank of a relation based on if it's part of a set of preconfigured networks (like US:). If these are not set, Planetiler uses other tags for hiking networks etc to figure out the rank. See the code here.

Here are two examples from Germany where this approach does not work properly which leaves major roads without road signs.
Motorway: https://www.openstreetmap.org/relation/2166961
Trunk: https://www.openstreetmap.org/relation/1506786

Expected behavior
As these are important roads, it would be good to have road signs for these roads.

Screenshots

Here is a comparison on z11 between OMT (has road signs) and Planetiler (no road signs):
Screenshot 2022-03-26 at 12 30 56
Screenshot 2022-03-26 at 12 31 19

Potential fix

The transportation_name_minor could be only used for minor roads. This would invalidate the fix for #145.

So how about we apply a low rank for relations with network=e-road and when getting the relations of a road, we order them by rank? So right now, the default rank is 3, so maybe e-roads could be rank 4?

[FEATURE] Support zoom-levels higher than 14

Planetiler currently limits the maximum zoom level to 14 since that was the highest needed for the OpenMapTiles port. Other schemas may want to go higher though. It should at least be possible to go to z15, and possibly z16.

[FEATURE] lower memory requirements for spares profiles

Is your feature request related to a problem? Please describe.
I want to render a profile on planet.osm.pbf which creates a small output mbtiles file which is maybe only 100 MB. Currently, I need a machine with 128 GB ram for this.

Describe the solution you'd like
Being able to render profiles which create small mbtiles files on machines with smaller amount of ram, e.g., 8 GB ram.

Describe alternatives you've considered
First, run osmium on planet.osm.pbf to extract only relevant features which results in a smaller .osm.pbf file. Then, run planetiler.

Additional context
Toilts example can do this to some extent:

Osmium: https://docs.osmcode.org/osmium/latest/osmium-tags-filter.html

Relevant planetiler code:

// TODO allow limiting node storage to only ones that profile cares about

`canBePoint`

There are these nice functions called canBeLine() and canBePolygon(). Do you think we could also have one called canBePoint()?

[FEATURE] PMTiles output format

Is your feature request related to a problem? Please describe.

Currently, Planetiler outputs mbtiles which requires a tileserver, i.e., static file hosting like on github pages is not enough to serve tiles.

Describe the solution you'd like

PMTiles can be used to serve vector tiles with range requests and they don't require a tile server. Planetiler could implement a pmtiles writer.

Describe alternatives you've considered

@bdon created a mbtiles to pmtiles converter:

pip install pmtiles
pmtiles-convert TILES.mbtiles TILES.pmtiles

Additional context
the powerlines example uses pmtiles https://github.com/wipfli/powerlines-switzerland

Example Request

Great project, the examples have been nice and concise and really great to work with.

Is there a way to also get the ocean polygons in with any of those examples at all?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.