Migrate to eclipse formatter to support multiple IDEs (#122)

pull/130/head
Michael Barry 2022-03-08 21:08:03 -05:00 zatwierdzone przez GitHub
rodzic bce75230f2
commit cce51668f2
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
119 zmienionych plików z 3330 dodań i 2518 usunięć

Wyświetl plik

@ -1,4 +1,5 @@
--- ---
name: Bug report name: Bug report
about: Create a report to help improve Planetiler about: Create a report to help improve Planetiler
title: "[BUG] " title: "[BUG] "

Wyświetl plik

@ -1,4 +1,5 @@
--- ---
name: Feature request name: Feature request
about: Suggest an idea for Planetiler about: Suggest an idea for Planetiler
title: "[FEATURE] " title: "[FEATURE] "

Wyświetl plik

@ -15,7 +15,8 @@ updates:
ignore: ignore:
- dependency-name: "com.graphhopper:graphhopper-reader-osm" - dependency-name: "com.graphhopper:graphhopper-reader-osm"
- package-ecosystem: maven - package-ecosystem: maven
directory: "/planetiler-examples" # workaround for https://github.com/dependabot/dependabot-core/issues/4425
directory: "/.github/planetiler-examples-dependabot"
open-pull-requests-limit: 1 open-pull-requests-limit: 1
schedule: schedule:
interval: daily interval: daily

Wyświetl plik

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This is just a workaround for https://github.com/dependabot/dependabot-core/issues/4425 so that
dependabot can update planetiler-examples/standalone.pom.xml without referring directly to a pom.xml with a
non-standard name.
-->
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>4.0.0</modelVersion>
<groupId>com.onthegomap.planetiler</groupId>
<artifactId>planetiler-examples-parent-for-dependabot</artifactId>
<version>HEAD</version>
<packaging>pom</packaging>
<modules>
<module>../../planetiler-examples/pom.xml</module>
</modules>
</project>

Wyświetl plik

@ -34,10 +34,10 @@ jobs:
cache: 'maven' cache: 'maven'
- name: Build with mvnw (linux/mac) - name: Build with mvnw (linux/mac)
if: ${{ !contains(matrix.os, 'windows') }} if: ${{ !contains(matrix.os, 'windows') }}
run: ./mvnw ${{matrix.args}} --batch-mode -no-transfer-progress package jib:buildTar --file pom.xml run: ./mvnw ${{matrix.args}} --batch-mode -no-transfer-progress package verify jib:buildTar --file pom.xml
- name: Build with mvnw.cmd (windows) - name: Build with mvnw.cmd (windows)
if: ${{ contains(matrix.os, 'windows') }} if: ${{ contains(matrix.os, 'windows') }}
run: mvnw.cmd ${{matrix.args}} --batch-mode -no-transfer-progress package jib:buildTar --file pom.xml run: mvnw.cmd ${{matrix.args}} --batch-mode -no-transfer-progress package verify jib:buildTar --file pom.xml
shell: cmd shell: cmd
regenerate: regenerate:
@ -54,7 +54,7 @@ jobs:
cache: 'maven' cache: 'maven'
- run: ./scripts/regenerate-openmaptiles.sh - run: ./scripts/regenerate-openmaptiles.sh
- run: ./mvnw -DskipTests --batch-mode -no-transfer-progress clean install -pl planetiler-basemap -am - run: ./mvnw -DskipTests --batch-mode -no-transfer-progress clean install -pl planetiler-basemap -am
- run: ./mvnw --batch-mode -no-transfer-progress test -pl planetiler-basemap - run: ./mvnw --batch-mode -no-transfer-progress verify -pl planetiler-basemap
examples: examples:
name: Example project name: Example project
@ -69,7 +69,7 @@ jobs:
java-version: 17 java-version: 17
distribution: 'temurin' distribution: 'temurin'
- name: Build and test - name: Build and test
run: mvn --batch-mode -no-transfer-progress package --file pom.xml run: mvn --batch-mode -no-transfer-progress package --file standalone.pom.xml
working-directory: planetiler-examples working-directory: planetiler-examples
- name: Find jar - name: Find jar
run: mv target/*with-deps.jar ./run.jar run: mv target/*with-deps.jar ./run.jar

8
.gitignore vendored
Wyświetl plik

@ -5,11 +5,19 @@ target/
!.mvn/wrapper/*.jar !.mvn/wrapper/*.jar
*.log *.log
# idea
*/.idea */.idea
.idea/* .idea/*
*.iml *.iml
!.idea/codeStyles !.idea/codeStyles
!.idea/vcs.xml !.idea/vcs.xml
!.idea/eclipseCodeFormatter.xml
# eclipse
.classpath
.project
.settings
bin/
TODO TODO

Wyświetl plik

@ -265,6 +265,7 @@
</indentOptions> </indentOptions>
</codeStyleSettings> </codeStyleSettings>
<codeStyleSettings language="XML"> <codeStyleSettings language="XML">
<option name="RIGHT_MARGIN" value="120" />
<indentOptions> <indentOptions>
<option name="INDENT_SIZE" value="2" /> <option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" /> <option name="CONTINUATION_INDENT_SIZE" value="2" />
@ -594,4 +595,4 @@
</indentOptions> </indentOptions>
</codeStyleSettings> </codeStyleSettings>
</code_scheme> </code_scheme>
</component> </component>

Wyświetl plik

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EclipseCodeFormatterProjectSettings">
<option name="projectSpecificProfile">
<ProjectSpecificProfile>
<option name="formatter" value="ECLIPSE" />
<option name="importOrder" value="#;" />
<option name="pathToConfigFileJava" value="$PROJECT_DIR$/eclipse-formatter.xml" />
<option name="selectedJavaProfile" value="Planetiler" />
</ProjectSpecificProfile>
</option>
</component>
</project>

5
.mvn/jvm.config 100644
Wyświetl plik

@ -0,0 +1,5 @@
--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED

11
.vscode/settings.json vendored 100644
Wyświetl plik

@ -0,0 +1,11 @@
{
"java.format.settings.url": "eclipse-formatter.xml",
"java.format.settings.profile": "Planetiler",
"java.completion.importOrder": [
"#",
""
],
"java.sources.organizeImports.staticStarThreshold": 5,
"java.sources.organizeImports.starThreshold": 999,
"java.saveActions.organizeImports": true
}

Wyświetl plik

@ -121,3 +121,4 @@ Finally, a single-threaded writer writes encoded vector tiles to the output MBTi
- Create the largest prepared statement supported by SQLite (999 parameters) - Create the largest prepared statement supported by SQLite (999 parameters)
- Iterate through finished vector tile batches until the prepared statement is full, flush to disk, then repeat - Iterate through finished vector tile batches until the prepared statement is full, flush to disk, then repeat
- Then flush any remaining tiles at the end - Then flush any remaining tiles at the end

Wyświetl plik

@ -1,6 +1,14 @@
# Contributing to Planetiler # Contributing to Planetiler
Pull requests are welcome! To set up your development environment: Pull requests are welcome! Any pull request should:
- Include at least one unit test to verify the change in behavior
- Include an end-to-end test
in [PlanetilerTests.java](planetiler-core/src/test/java/com/onthegomap/planetiler/PlanetilerTests.java)
to verify any major new user-facing features work
- Format the change `./mvnw spotless:apply` and test with `./mvnw verify` before pushing
To set up your local development environment:
- Fork the repo - Fork the repo
- Install Java 16 or later. You can download Java manually from [Adoptium](https://adoptium.net/installation.html) or - Install Java 16 or later. You can download Java manually from [Adoptium](https://adoptium.net/installation.html) or
@ -15,30 +23,57 @@ Pull requests are welcome! To set up your development environment:
- on windows: `mvnw.cmd clean test` - on windows: `mvnw.cmd clean test`
- or if you already have maven installed globally on your machine: `mvn clean test` - or if you already have maven installed globally on your machine: `mvn clean test`
To edit the code: GitHub Workflows will run regression tests on any pull request.
- [Install IntelliJ IDE](https://www.jetbrains.com/help/idea/installation-guide.html) ## IDE Setup
You can use any text editor as long as you format the code and test before pushing. A good IDE will make things a lot
easier though.
### IntelliJ IDEA (recommended)
- [Install IntelliJ IDEA](https://www.jetbrains.com/help/idea/installation-guide.html)
- Install
the [Adapter for Eclipse Code Formatter plugin](https://plugins.jetbrains.com/plugin/6546-adapter-for-eclipse-code-formatter)
- In IntelliJ, click `Open`, navigate to the the `pom.xml` file in the local copy of this repo, and `Open` - In IntelliJ, click `Open`, navigate to the the `pom.xml` file in the local copy of this repo, and `Open`
then `Open as Project` then `Open as Project`
- If IntelliJ asks (and you trust the code) then click `Trust Project` - If IntelliJ asks (and you trust the code) then click `Trust Project`
- If any java source files show "Cannot resolve symbol..." errors for Planetiler classes, you might need to - Under `Preferences -> Tools -> Actions on Save` (or `File -> Settings -> Tools -> Actions on Save` on Linux)
select: `File -> Invalidate Caches... -> Just Restart`. select `Reformat code` and `Optimize imports` to automatically format code on save.
- If you see a "Project JDK is not defined" error, then choose `Setup SDK` and point IntelliJ at the Java 16 or later
installed on your system
- Recommended: Under `Preferences -> Tools -> Actions on Save` (or `File -> Settings -> Tools -> Actions on Save` on Linux) select `Reformat code` and `Optimize imports` to
automatically format code on save.
- To verify everything works correctly, right click on `planetiler-core/src/test/java` folder and - To verify everything works correctly, right click on `planetiler-core/src/test/java` folder and
click `Run 'All Tests'` click `Run 'All Tests'`
Any pull request should: Troubleshooting:
- Include at least one unit test to verify the change in behavior - If any java source files show "Cannot resolve symbol..." errors for Planetiler classes, you might need to
- Include an end-to-end test select: `File -> Invalidate Caches... -> Just Restart`.
in [PlanetilerTests.java](planetiler-core/src/test/java/com/onthegomap/planetiler/PlanetilerTests.java) - If you see a "Project JDK is not defined" error, then choose `Setup SDK` and point IntelliJ at the Java 16 or later
to verify any major new user-facing features work installed on your system
- Use IntelliJ's auto-formatting for modified files (this should get enabled automatically)
- Be free of IntelliJ warnings for modified files
GitHub Workflows will run regression tests on any pull request. ### Visual Studio Code
TODO: Set up checkstyle and an auto-formatter to enforce standards, so you can use any IDE. - Install the [Extension Pack for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack)
- In VSCode, click `File -> Open` and navigate to Planetiler directory
- If VSCode asks (and you trust the code) then click `Yes I trust the authors`
- To verify everything works correctly, go to the `Testing` tab and click `Run Tests`
Learn more about using VSCode with Java [here](https://code.visualstudio.com/docs/languages/java).
### Eclipse
- In [Eclipse for Java Developers](https://www.eclipse.org/downloads/packages/), click `File -> Import ...`
then `Maven -> Existing Maven Projects`, navigate to Planetiler directory, and click `Finish`
- Under `Eclipse -> Preferences...`:
- Under `Java -> Code Style -> Formatter` and choose `Import...`
choose [`eclipse-formatter.xml`](eclipse-formatter.xml) from the root of this project. Then choose `Planetiler` as
the Active profile.
- Under `Java -> Editor -> Save Actions` check `Perform selected actions on save`, `Format source code`
, `Format all lines` and `Organize imports`
- Under `Java -> Code Style -> Organize Imports` change the `number of static imports needed for .*` to 5, then remove
the groups and add 2 new groups:
- `New Static...` and `*`
- `New...` and `*`
- To verify everything works correctly, right click on `planetiler-core/src/test/java` folder and
click `Run As -> JUnit Test`
TODO: Set up checkstyle

Wyświetl plik

@ -50,10 +50,11 @@ Additionally, the `planetiler-basemap` module is based on [OpenMapTiles](https:/
## Data ## Data
| source | license | used as default | included in repo | | source | license | used as default | included in repo |
|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------|-----------------|------------------| |----------------------------|--------------------------------------------------------------------------------------------------------------------------------------|-----------------|------------------|
| OpenStreetMap (OSM) data | [ODBL](https://www.openstreetmap.org/copyright) | yes | yes | | OpenStreetMap (OSM) data | [ODBL](https://www.openstreetmap.org/copyright) | yes | yes |
| Natural Earth | [public domain](https://www.naturalearthdata.com/about/terms-of-use/) | yes | yes | | Natural Earth | [public domain](https://www.naturalearthdata.com/about/terms-of-use/) | yes | yes |
| OSM Lakelines | [MIT](https://github.com/lukasmartinelli/osm-lakelines), data from OSM [ODBL](https://www.openstreetmap.org/copyright) | yes | no | | OSM Lakelines | [MIT](https://github.com/lukasmartinelli/osm-lakelines), data from OSM [ODBL](https://www.openstreetmap.org/copyright) | yes | no |
| OSM Water Polygons | [acknowledgement](https://osmdata.openstreetmap.de/info/license.html), data from OSM [ODBL](https://www.openstreetmap.org/copyright) | yes | yes | | OSM Water Polygons | [acknowledgement](https://osmdata.openstreetmap.de/info/license.html), data from OSM [ODBL](https://www.openstreetmap.org/copyright) | yes | yes |
| Wikidata name translations | [CCO](https://www.wikidata.org/wiki/Wikidata:Licensing) | no | no | | Wikidata name translations | [CCO](https://www.wikidata.org/wiki/Wikidata:Licensing) | no | no |

Wyświetl plik

@ -15,10 +15,12 @@ First decide where to get the `planet.osm.pbf` file:
- Or a [Daylight Distribution](https://daylightmap.org/) snapshot from Facebook that includes extra quality/consistency - Or a [Daylight Distribution](https://daylightmap.org/) snapshot from Facebook that includes extra quality/consistency
checks, and add-ons like ML-detected roads and buildings. Combine add-ons and re-number checks, and add-ons like ML-detected roads and buildings. Combine add-ons and re-number
using [osmium-tool](https://osmcode.org/osmium-tool/): using [osmium-tool](https://osmcode.org/osmium-tool/):
```bash ```bash
osmium apply-changes daylight.osm.pbf admin.osc.bz2 <buildings.osc.bz2, ...> -o everything.osm.pbf osmium apply-changes daylight.osm.pbf admin.osc.bz2 <buildings.osc.bz2, ...> -o everything.osm.pbf
osmium renumber everything.osm.pbf -o planet.osm.pbf osmium renumber everything.osm.pbf -o planet.osm.pbf
``` ```
NOTE: you need at least `admin.osc.bz2` for the `boundary` layer to show. This takes about 2.5 hours and needs as much NOTE: you need at least `admin.osc.bz2` for the `boundary` layer to show. This takes about 2.5 hours and needs as much
RAM as the `planet.osm.pbf` size. RAM as the `planet.osm.pbf` size.

Wyświetl plik

@ -118,7 +118,7 @@ See the [planetiler-examples](planetiler-examples) project.
Some example runtimes (excluding downloading resources): Some example runtimes (excluding downloading resources):
| Input | Profile | Machine | Time | mbtiles size | Logs | | Input | Profile | Machine | Time | mbtiles size | Logs |
|-------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------|----------------------------------------------------------|---------------------------|--------------|--------------------------------------------------------------------------------------------------------------------------------| |-------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------|----------------------------------------------------------|---------------------------|--------------|--------------------------------------------------------------------------------------------------------------------------------|
| s3://osm-pds/2021/planet-211011.osm.pbf (65GB) | Basemap | DO 16cpu 128GB | 3h9m cpu:42h1m avg:13.3 | 99GB | [logs](planet-logs/v0.1.0-planet-do-16cpu-128gb.txt), [VisualVM Profile](planet-logs/v0.1.0-planet-do-16cpu-128gb.nps) | | s3://osm-pds/2021/planet-211011.osm.pbf (65GB) | Basemap | DO 16cpu 128GB | 3h9m cpu:42h1m avg:13.3 | 99GB | [logs](planet-logs/v0.1.0-planet-do-16cpu-128gb.txt), [VisualVM Profile](planet-logs/v0.1.0-planet-do-16cpu-128gb.nps) |
| [Daylight Distribution v1.6](https://daylightmap.org/2021/09/29/daylight-v16-released.html) with ML buildings and admin boundaries (67GB) | Basemap | DO 16cpu 128GB | 3h13m cpu:43h40m avg:13.5 | 101GB | [logs](planet-logs/v0.1.0-daylight-do-16cpu-128gb.txt) | | [Daylight Distribution v1.6](https://daylightmap.org/2021/09/29/daylight-v16-released.html) with ML buildings and admin boundaries (67GB) | Basemap | DO 16cpu 128GB | 3h13m cpu:43h40m avg:13.5 | 101GB | [logs](planet-logs/v0.1.0-daylight-do-16cpu-128gb.txt) |

Wyświetl plik

@ -0,0 +1,480 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="21">
<profile kind="CodeFormatterProfile" name="Planetiler" version="21">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration"
value="preserve_positions"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="20"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments"
value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header"
value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="preserve_positions"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="84"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration"
value="preserve_positions"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header"
value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="preserve_positions"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration"
value="preserve_positions"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="17"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="-1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="120"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="48"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="separate_lines_if_wrapped"/>
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration"
value="preserve_positions"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
</profile>
</profiles>

Wyświetl plik

@ -27,15 +27,15 @@ import java.util.List;
* <p> * <p>
* Layer implementations extend these interfaces to subscribe to elements from different sources: * Layer implementations extend these interfaces to subscribe to elements from different sources:
* <ul> * <ul>
* <li>{@link LakeCenterlineProcessor}</li> * <li>{@link LakeCenterlineProcessor}</li>
* <li>{@link NaturalEarthProcessor}</li> * <li>{@link NaturalEarthProcessor}</li>
* <li>{@link OsmWaterPolygonProcessor}</li> * <li>{@link OsmWaterPolygonProcessor}</li>
* <li>{@link OsmAllProcessor} to process every OSM feature</li> * <li>{@link OsmAllProcessor} to process every OSM feature</li>
* <li>{@link OsmRelationPreprocessor} to process every OSM relation during first pass through OSM file</li> * <li>{@link OsmRelationPreprocessor} to process every OSM relation during first pass through OSM file</li>
* <li>A {@link Tables.RowHandler} implementation in {@code Tables.java} to process input features filtered and parsed * <li>A {@link Tables.RowHandler} implementation in {@code Tables.java} to process input features filtered and parsed
* according to the imposm3 mappings defined in the OpenMapTiles schema. Each element corresponds to a row in the * according to the imposm3 mappings defined in the OpenMapTiles schema. Each element corresponds to a row in the table
* table that imposm3 would have generated, with generated methods for accessing the data that would have been in each * that imposm3 would have generated, with generated methods for accessing the data that would have been in each
* column</li> * column</li>
* </ul> * </ul>
* Layers can also subscribe to notifications when we finished processing an input source by implementing * Layers can also subscribe to notifications when we finished processing an input source by implementing
* {@link FinishHandler} or post-process features in that layer before rendering the output tile by implementing * {@link FinishHandler} or post-process features in that layer before rendering the output tile by implementing
@ -118,9 +118,8 @@ public class BasemapProfile extends ForwardingProfile {
return new RowDispatch(constructor.create(), handlers); return new RowDispatch(constructor.create(), handlers);
}).simplify().index(); }).simplify().index();
wikidataMappings = Tables.MAPPINGS wikidataMappings = Tables.MAPPINGS
.mapResults(constructor -> .mapResults(constructor -> handlerMap.getOrDefault(constructor.rowClass(), List.of()).stream()
handlerMap.getOrDefault(constructor.rowClass(), List.of()).stream() .anyMatch(handler -> !IgnoreWikidata.class.isAssignableFrom(handler.handlerClass()))
.anyMatch(handler -> !IgnoreWikidata.class.isAssignableFrom(handler.handlerClass()))
).filterResults(b -> b).simplify().index(); ).filterResults(b -> b).simplify().index();
// register a handler for all OSM elements that forwards to imposm3 "table row" handler methods // register a handler for all OSM elements that forwards to imposm3 "table row" handler methods
@ -149,8 +148,8 @@ public class BasemapProfile extends ForwardingProfile {
if (elem instanceof OsmElement.Node) { if (elem instanceof OsmElement.Node) {
return wikidataMappings.getOrElse(SimpleFeature.create(EMPTY_POINT, tags), false); return wikidataMappings.getOrElse(SimpleFeature.create(EMPTY_POINT, tags), false);
} else if (elem instanceof OsmElement.Way) { } else if (elem instanceof OsmElement.Way) {
return wikidataMappings.getOrElse(SimpleFeature.create(EMPTY_POLYGON, tags), false) return wikidataMappings.getOrElse(SimpleFeature.create(EMPTY_POLYGON, tags), false) ||
|| wikidataMappings.getOrElse(SimpleFeature.create(EMPTY_LINE, tags), false); wikidataMappings.getOrElse(SimpleFeature.create(EMPTY_LINE, tags), false);
} else if (elem instanceof OsmElement.Relation) { } else if (elem instanceof OsmElement.Relation) {
return wikidataMappings.getOrElse(SimpleFeature.create(EMPTY_POLYGON, tags), false); return wikidataMappings.getOrElse(SimpleFeature.create(EMPTY_POLYGON, tags), false);
} else { } else {
@ -201,14 +200,13 @@ public class BasemapProfile extends ForwardingProfile {
} }
/** /**
* Layers should implement this interface to subscribe to elements from <a href="https://www.naturalearthdata.com/">natural * Layers should implement this interface to subscribe to elements from
* earth</a>. * <a href="https://www.naturalearthdata.com/">natural earth</a>.
*/ */
public interface NaturalEarthProcessor { public interface NaturalEarthProcessor {
/** /**
* Process an element from {@code table} in the<a href="https://www.naturalearthdata.com/">natural earth * Process an element from {@code table} in the<a href="https://www.naturalearthdata.com/">natural earth source</a>.
* source</a>.
* *
* @see Profile#processFeature(SourceFeature, FeatureCollector) * @see Profile#processFeature(SourceFeature, FeatureCollector)
*/ */
@ -216,8 +214,8 @@ public class BasemapProfile extends ForwardingProfile {
} }
/** /**
* Layers should implement this interface to subscribe to elements from <a href="https://github.com/lukasmartinelli/osm-lakelines">OSM * Layers should implement this interface to subscribe to elements from
* lake centerlines source</a>. * <a href="https://github.com/lukasmartinelli/osm-lakelines">OSM lake centerlines source</a>.
*/ */
public interface LakeCenterlineProcessor { public interface LakeCenterlineProcessor {
@ -231,8 +229,8 @@ public class BasemapProfile extends ForwardingProfile {
} }
/** /**
* Layers should implement this interface to subscribe to elements from <a href="https://osmdata.openstreetmap.de/data/water-polygons.html">OSM * Layers should implement this interface to subscribe to elements from
* water polygons source</a>. * <a href="https://osmdata.openstreetmap.de/data/water-polygons.html">OSM water polygons source</a>.
*/ */
public interface OsmWaterPolygonProcessor { public interface OsmWaterPolygonProcessor {

Wyświetl plik

@ -38,14 +38,14 @@ import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
/** /**
* Generates code in the {@code generated} package from the OpenMapTiles schema crawled from a tag or branch in the <a * Generates code in the {@code generated} package from the OpenMapTiles schema crawled from a tag or branch in the
* href="https://github.com/openmaptiles/openmaptiles">OpenMapTiles GitHub repo</a>. * <a href="https://github.com/openmaptiles/openmaptiles">OpenMapTiles GitHub repo</a>.
* <p> * <p>
* {@code OpenMapTilesSchema.java} contains the output layer definitions (i.e. attributes and allowed values) so that * {@code OpenMapTilesSchema.java} contains the output layer definitions (i.e. attributes and allowed values) so that
* layer implementations in {@code layers} package can reference them instead of hard-coding. * layer implementations in {@code layers} package can reference them instead of hard-coding.
* <p> * <p>
* {@code Tables.java} contains the <a href="https://github.com/omniscale/imposm3">imposm3</a> table definitions from * {@code Tables.java} contains the <a href="https://github.com/omniscale/imposm3">imposm3</a> table definitions from
* mapping.yaml files in the OpenMapTiles repo. Layers in the {@code layer} package can extend the {@code Handler} * mapping.yaml files in the OpenMapTiles repo. Layers in the {@code layer} package can extend the {@code Handler}
* nested class for a table definition to "subscribe" to OSM elements that imposm3 would put in that table. * nested class for a table definition to "subscribe" to OSM elements that imposm3 would put in that table.
* <p> * <p>
* To run use {@code ./scripts/regenerate-openmaptiles.sh} * To run use {@code ./scripts/regenerate-openmaptiles.sh}
@ -169,8 +169,7 @@ public class Generate {
emitLayerSchemaDefinitions(config.tileset, layers, packageName, output, tag); emitLayerSchemaDefinitions(config.tileset, layers, packageName, output, tag);
emitTableDefinitions(tables, packageName, output, tag); emitTableDefinitions(tables, packageName, output, tag);
LOGGER.info( LOGGER.info("Done!");
"Done generating code in 'generated' package, now run IntelliJ 'Reformat Code' operation with 'Optimize imports' and 'Cleanup code' options selected.");
} }
/** Generates {@code OpenMapTilesSchema.java} */ /** Generates {@code OpenMapTilesSchema.java} */
@ -178,56 +177,57 @@ public class Generate {
Path output, String tag) Path output, String tag)
throws IOException { throws IOException {
StringBuilder schemaClass = new StringBuilder(); StringBuilder schemaClass = new StringBuilder();
schemaClass.append(""" schemaClass.append(
%s
package %s;
import static com.onthegomap.planetiler.expression.Expression.*;
import com.onthegomap.planetiler.config.PlanetilerConfig;
import com.onthegomap.planetiler.stats.Stats;
import com.onthegomap.planetiler.expression.MultiExpression;
import com.onthegomap.planetiler.basemap.Layer;
import com.onthegomap.planetiler.util.Translations;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* All vector tile layer definitions, attributes, and allowed values generated from the
* <a href="https://github.com/openmaptiles/openmaptiles/blob/%s/openmaptiles.yaml">OpenMapTiles vector tile schema %s</a>.
*/
@SuppressWarnings("unused")
public class OpenMapTilesSchema {
public static final String NAME = %s;
public static final String DESCRIPTION = %s;
public static final String VERSION = %s;
public static final String ATTRIBUTION = %s;
public static final List<String> LANGUAGES = List.of(%s);
/** Returns a list of expected layer implementation instances from the {@code layers} package. */
public static List<Layer> createInstances(Translations translations, PlanetilerConfig config, Stats stats) {
return List.of(
%s
);
}
""" """
.formatted( %s
GENERATED_FILE_HEADER, package %s;
packageName,
escapeJavadoc(tag), import static com.onthegomap.planetiler.expression.Expression.*;
escapeJavadoc(tag), import com.onthegomap.planetiler.config.PlanetilerConfig;
Format.quote(info.name), import com.onthegomap.planetiler.stats.Stats;
Format.quote(info.description), import com.onthegomap.planetiler.expression.MultiExpression;
Format.quote(info.version), import com.onthegomap.planetiler.basemap.Layer;
Format.quote(info.attribution), import com.onthegomap.planetiler.util.Translations;
info.languages.stream().map(Format::quote).collect(joining(", ")), import java.util.List;
layers.stream() import java.util.Map;
.map( import java.util.Set;
l -> "new com.onthegomap.planetiler.basemap.layers.%s(translations, config, stats)"
.formatted(lowerUnderscoreToUpperCamel(l.layer.id))) /**
.collect(joining("," + LINE_SEPARATOR)) * All vector tile layer definitions, attributes, and allowed values generated from the
.indent(6).trim() * <a href="https://github.com/openmaptiles/openmaptiles/blob/%s/openmaptiles.yaml">OpenMapTiles vector tile schema %s</a>.
)); */
@SuppressWarnings("unused")
public class OpenMapTilesSchema {
public static final String NAME = %s;
public static final String DESCRIPTION = %s;
public static final String VERSION = %s;
public static final String ATTRIBUTION = %s;
public static final List<String> LANGUAGES = List.of(%s);
/** Returns a list of expected layer implementation instances from the {@code layers} package. */
public static List<Layer> createInstances(Translations translations, PlanetilerConfig config, Stats stats) {
return List.of(
%s
);
}
"""
.formatted(
GENERATED_FILE_HEADER,
packageName,
escapeJavadoc(tag),
escapeJavadoc(tag),
Format.quote(info.name),
Format.quote(info.description),
Format.quote(info.version),
Format.quote(info.attribution),
info.languages.stream().map(Format::quote).collect(joining(", ")),
layers.stream()
.map(
l -> "new com.onthegomap.planetiler.basemap.layers.%s(translations, config, stats)"
.formatted(lowerUnderscoreToUpperCamel(l.layer.id)))
.collect(joining("," + LINE_SEPARATOR))
.indent(6).trim()
));
for (var layer : layers) { for (var layer : layers) {
String layerCode = generateCodeForLayer(tag, layer); String layerCode = generateCodeForLayer(tag, layer);
schemaClass.append(layerCode); schemaClass.append(layerCode);
@ -344,68 +344,70 @@ public class Generate {
String tag) String tag)
throws IOException { throws IOException {
StringBuilder tablesClass = new StringBuilder(); StringBuilder tablesClass = new StringBuilder();
tablesClass.append(""" tablesClass.append(
%s """
package %s; %s
package %s;
import static com.onthegomap.planetiler.expression.Expression.*; import static com.onthegomap.planetiler.expression.Expression.*;
import com.onthegomap.planetiler.expression.Expression; import com.onthegomap.planetiler.expression.Expression;
import com.onthegomap.planetiler.expression.MultiExpression; import com.onthegomap.planetiler.expression.MultiExpression;
import com.onthegomap.planetiler.FeatureCollector; import com.onthegomap.planetiler.FeatureCollector;
import com.onthegomap.planetiler.reader.SourceFeature; import com.onthegomap.planetiler.reader.SourceFeature;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
* OSM element parsers generated from the <a href="https://github.com/omniscale/imposm3">imposm3</a> table definitions * OSM element parsers generated from the <a href="https://github.com/omniscale/imposm3">imposm3</a> table definitions
* in the <a href="https://github.com/openmaptiles/openmaptiles/blob/%s/openmaptiles.yaml">OpenMapTiles vector tile schema</a>. * in the <a href="https://github.com/openmaptiles/openmaptiles/blob/%s/openmaptiles.yaml">OpenMapTiles vector tile schema</a>.
* *
* These filter and parse the raw OSM key/value attribute pairs on tags into records with fields that match the * These filter and parse the raw OSM key/value attribute pairs on tags into records with fields that match the
* columns in the tables that imposm3 would generate. Layer implementations can "subscribe" to elements from each * columns in the tables that imposm3 would generate. Layer implementations can "subscribe" to elements from each
* "table" but implementing the table's {@code Handler} interface and use the element's typed API to access * "table" but implementing the table's {@code Handler} interface and use the element's typed API to access
* attributes. * attributes.
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class Tables { public class Tables {
/** A parsed OSM element that would appear in a "row" of the imposm3 table. */ /** A parsed OSM element that would appear in a "row" of the imposm3 table. */
public interface Row { public interface Row {
/** Returns the original OSM element. */ /** Returns the original OSM element. */
SourceFeature source(); SourceFeature source();
} }
/** A functional interface that the constructor of a new table row can be coerced to. */ /** A functional interface that the constructor of a new table row can be coerced to. */
@FunctionalInterface @FunctionalInterface
public interface Constructor { public interface Constructor {
Row create(SourceFeature source, String mappingKey); Row create(SourceFeature source, String mappingKey);
} }
/** The {@code rowClass} of an imposm3 table row and its constructor coerced to a {@link Constructor}. */ /** The {@code rowClass} of an imposm3 table row and its constructor coerced to a {@link Constructor}. */
public record RowClassAndConstructor( public record RowClassAndConstructor(
Class<? extends Row> rowClass, Class<? extends Row> rowClass,
Constructor create Constructor create
) {} ) {}
/** A functional interface that the typed handler method that a layer implementation can be coerced to. */ /** A functional interface that the typed handler method that a layer implementation can be coerced to. */
@FunctionalInterface @FunctionalInterface
public interface RowHandler<T extends Row> { public interface RowHandler<T extends Row> {
/** Process a typed element according to the profile. */ /** Process a typed element according to the profile. */
void process(T element, FeatureCollector features); void process(T element, FeatureCollector features);
} }
/** The {@code handlerClass} of a layer handler and it's {@code process} method coerced to a {@link RowHandler}. */ /** The {@code handlerClass} of a layer handler and it's {@code process} method coerced to a {@link RowHandler}. */
public record RowHandlerAndClass<T extends Row>( public record RowHandlerAndClass<T extends Row>(
Class<?> handlerClass, Class<?> handlerClass,
RowHandler<T> handler RowHandler<T> handler
) {} ) {}
""".formatted(GENERATED_FILE_HEADER, packageName, escapeJavadoc(tag))); """
.formatted(GENERATED_FILE_HEADER, packageName, escapeJavadoc(tag)));
List<String> classNames = new ArrayList<>(); List<String> classNames = new ArrayList<>();
Map<String, String> fieldNameToType = new TreeMap<>(); Map<String, String> fieldNameToType = new TreeMap<>();
@ -489,17 +491,19 @@ public class Generate {
)); ));
""".formatted( """.formatted(
classNames.stream().map( classNames.stream().map(
className -> "MultiExpression.entry(new RowClassAndConstructor(%s.class, %s::new), %s.MAPPING)".formatted( className -> "MultiExpression.entry(new RowClassAndConstructor(%s.class, %s::new), %s.MAPPING)".formatted(
className, className, className)) className, className, className))
.collect(joining("," + LINE_SEPARATOR)).indent(2).strip() .collect(joining("," + LINE_SEPARATOR)).indent(2).strip()
).indent(2)); ).indent(2));
String handlerCondition = classNames.stream().map(className -> String handlerCondition = classNames.stream()
""" .map(
if (handler instanceof %s.Handler typedHandler) { className -> """
result.computeIfAbsent(%s.class, cls -> new ArrayList<>()).add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process)); if (handler instanceof %s.Handler typedHandler) {
}""".formatted(className, className) result.computeIfAbsent(%s.class, cls -> new ArrayList<>()).add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process));
).collect(joining(LINE_SEPARATOR)); }"""
.formatted(className, className)
).collect(joining(LINE_SEPARATOR));
tablesClass.append(""" tablesClass.append("""
/** /**
* Returns a map from imposm3 "table row" class to the layers that have a handler for it from a list of layer * Returns a map from imposm3 "table row" class to the layers that have a handler for it from a list of layer
@ -518,15 +522,15 @@ public class Generate {
} }
/** /**
* Returns an {@link Expression} that implements the same logic as the <a href="https://imposm.org/docs/imposm3/latest/mapping.html">Imposm3 * Returns an {@link Expression} that implements the same logic as the
* Data Mapping</a> definition for a table. * <a href="https://imposm.org/docs/imposm3/latest/mapping.html">Imposm3 Data Mapping</a> definition for a table.
*/ */
static Expression parseImposm3MappingExpression(Imposm3Table table) { static Expression parseImposm3MappingExpression(Imposm3Table table) {
if (table.type_mappings != null) { if (table.type_mappings != null) {
return or( return or(
table.type_mappings.entrySet().stream().map(entry -> table.type_mappings.entrySet().stream()
parseImposm3MappingExpression(entry.getKey(), entry.getValue(), table.filters) .map(entry -> parseImposm3MappingExpression(entry.getKey(), entry.getValue(), table.filters)
).toList() ).toList()
).simplify(); ).simplify();
} else { } else {
return parseImposm3MappingExpression(table.type, table.mapping, table.filters); return parseImposm3MappingExpression(table.type, table.mapping, table.filters);
@ -534,8 +538,8 @@ public class Generate {
} }
/** /**
* Returns an {@link Expression} that implements the same logic as the <a href="https://imposm.org/docs/imposm3/latest/mapping.html#filters">Imposm3 * Returns an {@link Expression} that implements the same logic as the
* Data Mapping filters</a> for a table. * <a href="https://imposm.org/docs/imposm3/latest/mapping.html#filters">Imposm3 Data Mapping filters</a> for a table.
*/ */
static Expression parseImposm3MappingExpression(String type, JsonNode mapping, Imposm3Filters filters) { static Expression parseImposm3MappingExpression(String type, JsonNode mapping, Imposm3Filters filters) {
return and( return and(

Wyświetl plik

@ -51,7 +51,8 @@ import com.onthegomap.planetiler.util.Translations;
/** /**
* Defines the logic for generating map elements in the {@code aerodrome_label} layer from source features. * Defines the logic for generating map elements in the {@code aerodrome_label} layer from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/aerodrome_label">OpenMapTiles * This class is ported to Java from
* <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/aerodrome_label">OpenMapTiles
* aerodrome_layer sql files</a>. * aerodrome_layer sql files</a>.
*/ */
public class AerodromeLabel implements public class AerodromeLabel implements

Wyświetl plik

@ -45,8 +45,8 @@ import com.onthegomap.planetiler.util.Translations;
/** /**
* Defines the logic for generating map elements in the {@code aeroway} layer from source features. * Defines the logic for generating map elements in the {@code aeroway} layer from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/aeroway">OpenMapTiles * This class is ported to Java from
* aeroway sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/aeroway">OpenMapTiles aeroway sql files</a>.
*/ */
public class Aeroway implements public class Aeroway implements
OpenMapTilesSchema.Aeroway, OpenMapTilesSchema.Aeroway,
@ -54,8 +54,7 @@ public class Aeroway implements
Tables.OsmAerowayPolygon.Handler, Tables.OsmAerowayPolygon.Handler,
Tables.OsmAerowayPoint.Handler { Tables.OsmAerowayPoint.Handler {
public Aeroway(Translations translations, PlanetilerConfig config, Stats stats) { public Aeroway(Translations translations, PlanetilerConfig config, Stats stats) {}
}
@Override @Override
public void process(Tables.OsmAerowayPolygon element, FeatureCollector features) { public void process(Tables.OsmAerowayPolygon element, FeatureCollector features) {

Wyświetl plik

@ -86,8 +86,9 @@ import org.slf4j.LoggerFactory;
* Defines the logic for generating map elements for country, state, and town boundaries in the {@code boundary} layer * Defines the logic for generating map elements for country, state, and town boundaries in the {@code boundary} layer
* from source features. * from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/boundary">OpenMapTiles * This class is ported to Java from
* boundary sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/boundary">OpenMapTiles boundary sql
* files</a>.
*/ */
public class Boundary implements public class Boundary implements
OpenMapTilesSchema.Boundary, OpenMapTilesSchema.Boundary,
@ -164,13 +165,13 @@ public class Boundary implements
BoundaryInfo info = switch (table) { BoundaryInfo info = switch (table) {
case "ne_110m_admin_0_boundary_lines_land" -> new BoundaryInfo(2, 0, 0); case "ne_110m_admin_0_boundary_lines_land" -> new BoundaryInfo(2, 0, 0);
case "ne_50m_admin_0_boundary_lines_land" -> new BoundaryInfo(2, 1, 3); case "ne_50m_admin_0_boundary_lines_land" -> new BoundaryInfo(2, 1, 3);
case "ne_10m_admin_0_boundary_lines_land" -> feature.hasTag("featurecla", "Lease Limit") ? null case "ne_10m_admin_0_boundary_lines_land" -> feature.hasTag("featurecla", "Lease Limit") ? null :
: new BoundaryInfo(2, 4, 4); new BoundaryInfo(2, 4, 4);
case "ne_10m_admin_1_states_provinces_lines" -> { case "ne_10m_admin_1_states_provinces_lines" -> {
Double minZoom = Parse.parseDoubleOrNull(feature.getTag("min_zoom")); Double minZoom = Parse.parseDoubleOrNull(feature.getTag("min_zoom"));
yield minZoom != null && minZoom <= 7 ? new BoundaryInfo(4, 1, 4) : yield minZoom != null && minZoom <= 7 ? new BoundaryInfo(4, 1, 4) :
minZoom != null && minZoom <= 7.7 ? new BoundaryInfo(4, 4, 4) : minZoom != null && minZoom <= 7.7 ? new BoundaryInfo(4, 4, 4) :
null; null;
} }
default -> null; default -> null;
}; };
@ -250,8 +251,8 @@ public class Boundary implements
int minzoom = int minzoom =
(maritime && minAdminLevel == 2) ? 4 : (maritime && minAdminLevel == 2) ? 4 :
minAdminLevel <= 4 ? 5 : minAdminLevel <= 4 ? 5 :
minAdminLevel <= 6 ? 9 : minAdminLevel <= 6 ? 9 :
minAdminLevel <= 8 ? 11 : 12; minAdminLevel <= 8 ? 11 : 12;
if (addCountryNames && !regionIds.isEmpty()) { if (addCountryNames && !regionIds.isEmpty()) {
// save for later // save for later
try { try {
@ -398,8 +399,7 @@ public class Boundary implements
try { try {
Geometry combined = polygonizer.getGeometry().union(); Geometry combined = polygonizer.getGeometry().union();
if (combined.isEmpty()) { if (combined.isEmpty()) {
LOGGER.warn("Unable to form closed polygon for OSM relation " + regionId LOGGER.warn("Unable to form closed polygon for OSM relation " + regionId + " (likely missing edges)");
+ " (likely missing edges)");
} else { } else {
countryBoundaries.put(regionId, PreparedGeometryFactory.prepare(combined)); countryBoundaries.put(regionId, PreparedGeometryFactory.prepare(combined));
} }
@ -429,8 +429,7 @@ public class Boundary implements
} }
/** /**
* Minimal set of information extracted from a boundary relation to be used when processing each way in that * Minimal set of information extracted from a boundary relation to be used when processing each way in that relation.
* relation.
*/ */
private record BoundaryRelation( private record BoundaryRelation(
long id, long id,
@ -443,17 +442,15 @@ public class Boundary implements
@Override @Override
public long estimateMemoryUsageBytes() { public long estimateMemoryUsageBytes() {
return CLASS_HEADER_BYTES return CLASS_HEADER_BYTES + MemoryEstimator.estimateSizeLong(id) + MemoryEstimator.estimateSizeInt(adminLevel) +
+ MemoryEstimator.estimateSizeLong(id) estimateSize(disputed) + POINTER_BYTES + estimateSize(name) + POINTER_BYTES + estimateSize(claimedBy) +
+ MemoryEstimator.estimateSizeInt(adminLevel) POINTER_BYTES + estimateSize(iso3166alpha3);
+ estimateSize(disputed)
+ POINTER_BYTES + estimateSize(name)
+ POINTER_BYTES + estimateSize(claimedBy)
+ POINTER_BYTES + estimateSize(iso3166alpha3);
} }
} }
/** Information to hold onto from processing a way in a boundary relation to determine the left/right region ID later. */ /**
* Information to hold onto from processing a way in a boundary relation to determine the left/right region ID later.
*/
private record CountryBoundaryComponent( private record CountryBoundaryComponent(
int adminLevel, int adminLevel,
boolean disputed, boolean disputed,

Wyświetl plik

@ -60,8 +60,9 @@ import java.util.Map;
/** /**
* Defines the logic for generating map elements for buildings in the {@code building} layer from source features. * Defines the logic for generating map elements for buildings in the {@code building} layer from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/building">OpenMapTiles * This class is ported to Java from
* building sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/building">OpenMapTiles building sql
* files</a>.
*/ */
public class Building implements public class Building implements
OpenMapTilesSchema.Building, OpenMapTilesSchema.Building,
@ -154,10 +155,8 @@ public class Building implements
parseDoubleOrNull(element.buildingminLevel()) parseDoubleOrNull(element.buildingminLevel())
); );
int renderHeight = (int) Math.ceil(height != null ? height int renderHeight = (int) Math.ceil(height != null ? height : levels != null ? (levels * 3.66) : 5);
: levels != null ? (levels * 3.66) : 5); int renderMinHeight = (int) Math.floor(minHeight != null ? minHeight : minLevels != null ? (minLevels * 3.66) : 0);
int renderMinHeight = (int) Math.floor(minHeight != null ? minHeight
: minLevels != null ? (minLevels * 3.66) : 0);
if (renderHeight < 3660 && renderMinHeight < 3660) { if (renderHeight < 3660 && renderMinHeight < 3660) {
var feature = features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE) var feature = features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE)

Wyświetl plik

@ -45,15 +45,15 @@ import com.onthegomap.planetiler.util.Translations;
/** /**
* Defines the logic for generating map elements in the {@code housenumber} layer from source features. * Defines the logic for generating map elements in the {@code housenumber} layer from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/housenumber">OpenMapTiles * This class is ported to Java from
* housenumber sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/housenumber">OpenMapTiles housenumber sql
* files</a>.
*/ */
public class Housenumber implements public class Housenumber implements
OpenMapTilesSchema.Housenumber, OpenMapTilesSchema.Housenumber,
Tables.OsmHousenumberPoint.Handler { Tables.OsmHousenumberPoint.Handler {
public Housenumber(Translations translations, PlanetilerConfig config, Stats stats) { public Housenumber(Translations translations, PlanetilerConfig config, Stats stats) {}
}
@Override @Override
public void process(Tables.OsmHousenumberPoint element, FeatureCollector features) { public void process(Tables.OsmHousenumberPoint element, FeatureCollector features) {

Wyświetl plik

@ -57,8 +57,9 @@ import java.util.Set;
* Defines the logic for generating map elements for natural land cover polygons like ice, sand, and forest in the * Defines the logic for generating map elements for natural land cover polygons like ice, sand, and forest in the
* {@code landcover} layer from source features. * {@code landcover} layer from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/landcover">OpenMapTiles * This class is ported to Java from
* landcover sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/landcover">OpenMapTiles landcover sql
* files</a>.
*/ */
public class Landcover implements public class Landcover implements
OpenMapTilesSchema.Landcover, OpenMapTilesSchema.Landcover,

Wyświetl plik

@ -55,8 +55,8 @@ import java.util.Set;
* Defines the logic for generating map elements for man-made land use polygons like cemeteries, zoos, and hospitals in * Defines the logic for generating map elements for man-made land use polygons like cemeteries, zoos, and hospitals in
* the {@code landuse} layer from source features. * the {@code landuse} layer from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/landuse">OpenMapTiles * This class is ported to Java from
* landuse sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/landuse">OpenMapTiles landuse sql files</a>.
*/ */
public class Landuse implements public class Landuse implements
OpenMapTilesSchema.Landuse, OpenMapTilesSchema.Landuse,
@ -75,8 +75,7 @@ public class Landuse implements
FieldValues.CLASS_NEIGHBOURHOOD FieldValues.CLASS_NEIGHBOURHOOD
); );
public Landuse(Translations translations, PlanetilerConfig config, Stats stats) { public Landuse(Translations translations, PlanetilerConfig config, Stats stats) {}
}
@Override @Override
public void processNaturalEarth(String table, SourceFeature feature, FeatureCollector features) { public void processNaturalEarth(String table, SourceFeature feature, FeatureCollector features) {

Wyświetl plik

@ -65,8 +65,9 @@ import org.slf4j.LoggerFactory;
* Defines the logic for generating map elements for mountain peak label points in the {@code mountain_peak} layer from * Defines the logic for generating map elements for mountain peak label points in the {@code mountain_peak} layer from
* source features. * source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/mountain_peak">OpenMapTiles * This class is ported to Java from
* mountain_peak sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/mountain_peak">OpenMapTiles mountain_peak
* sql files</a>.
*/ */
public class MountainPeak implements public class MountainPeak implements
BasemapProfile.NaturalEarthProcessor, BasemapProfile.NaturalEarthProcessor,

Wyświetl plik

@ -62,8 +62,8 @@ import java.util.Locale;
* Defines the logic for generating map elements for designated parks polygons and their label points in the {@code * Defines the logic for generating map elements for designated parks polygons and their label points in the {@code
* park} layer from source features. * park} layer from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/park">OpenMapTiles * This class is ported to Java from
* park sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/park">OpenMapTiles park sql files</a>.
*/ */
public class Park implements public class Park implements
OpenMapTilesSchema.Park, OpenMapTilesSchema.Park,

Wyświetl plik

@ -76,8 +76,8 @@ import org.locationtech.jts.geom.Point;
* Defines the logic for generating label points for populated places like continents, countries, cities, and towns in * Defines the logic for generating label points for populated places like continents, countries, cities, and towns in
* the {@code place} layer from source features. * the {@code place} layer from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/place">OpenMapTiles * This class is ported to Java from
* place sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/place">OpenMapTiles place sql files</a>.
*/ */
public class Place implements public class Place implements
OpenMapTilesSchema.Place, OpenMapTilesSchema.Place,
@ -142,11 +142,11 @@ public class Place implements
// ORDER BY "rank" ASC NULLS LAST, // ORDER BY "rank" ASC NULLS LAST,
.orderByInt(rank == null ? 15 : rank, 0, 15) // 4 bits .orderByInt(rank == null ? 15 : rank, 0, 15) // 4 bits
// place ASC NULLS LAST, // place ASC NULLS LAST,
.thenByInt(place == null ? 15 : place.ordinal(), 0, 15) // 4 bits .thenByInt(place == null ? 15 : place.ordinal(), 0, 15) // 4 bits
// population DESC NULLS LAST, // population DESC NULLS LAST,
.thenByLog(population, MAX_CITY_POPULATION, 1, 1 << (SORT_KEY_BITS - 13) - 1) .thenByLog(population, MAX_CITY_POPULATION, 1, 1 << (SORT_KEY_BITS - 13) - 1)
// length(name) ASC // length(name) ASC
.thenByInt(name == null ? 0 : name.length(), 0, 31) // 5 bits .thenByInt(name == null ? 0 : name.length(), 0, 31) // 5 bits
.get(); .get();
} }
@ -340,9 +340,9 @@ public class Place implements
int minzoom = rank != null && rank == 1 ? 2 : int minzoom = rank != null && rank == 1 ? 2 :
rank != null && rank <= 8 ? Math.max(3, rank - 1) : rank != null && rank <= 8 ? Math.max(3, rank - 1) :
placeType.ordinal() <= PlaceType.TOWN.ordinal() ? 7 : placeType.ordinal() <= PlaceType.TOWN.ordinal() ? 7 :
placeType.ordinal() <= PlaceType.VILLAGE.ordinal() ? 8 : placeType.ordinal() <= PlaceType.VILLAGE.ordinal() ? 8 :
placeType.ordinal() <= PlaceType.SUBURB.ordinal() ? 11 : 14; placeType.ordinal() <= PlaceType.SUBURB.ordinal() ? 11 : 14;
var feature = features.point(LAYER_NAME).setBufferPixels(BUFFER_SIZE) var feature = features.point(LAYER_NAME).setBufferPixels(BUFFER_SIZE)
.putAttrs(LanguageUtils.getNames(element.source().tags(), translations)) .putAttrs(LanguageUtils.getNames(element.source().tags(), translations))
@ -420,9 +420,7 @@ public class Place implements
} }
/** /**
* Information extracted from a natural earth place label that will be inspected when joining with OpenStreetMap * Information extracted from a natural earth place label that will be inspected when joining with OpenStreetMap data.
* data.
*/ */
private record NaturalEarthPoint(String name, String wikidata, int scaleRank, Set<String> names) {} private record NaturalEarthPoint(String name, String wikidata, int scaleRank, Set<String> names) {}
} }

Wyświetl plik

@ -61,8 +61,8 @@ import java.util.Map;
* Defines the logic for generating map elements for things like shops, parks, and schools in the {@code poi} layer from * Defines the logic for generating map elements for things like shops, parks, and schools in the {@code poi} layer from
* source features. * source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/poi">OpenMapTiles * This class is ported to Java from
* poi sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/poi">OpenMapTiles poi sql files</a>.
*/ */
public class Poi implements public class Poi implements
OpenMapTilesSchema.Poi, OpenMapTilesSchema.Poi,
@ -136,19 +136,8 @@ public class Poi implements
setupPoiFeature(element, features.centroidIfConvex(LAYER_NAME)); setupPoiFeature(element, features.centroidIfConvex(LAYER_NAME));
} }
private <T extends private <T extends Tables.WithSubclass & Tables.WithStation & Tables.WithFunicular & Tables.WithSport & Tables.WithInformation & Tables.WithReligion & Tables.WithMappingKey & Tables.WithName & Tables.WithIndoor & Tables.WithLayer & Tables.WithSource> void setupPoiFeature(
Tables.WithSubclass & T element, FeatureCollector.Feature output) {
Tables.WithStation &
Tables.WithFunicular &
Tables.WithSport &
Tables.WithInformation &
Tables.WithReligion &
Tables.WithMappingKey &
Tables.WithName &
Tables.WithIndoor &
Tables.WithLayer &
Tables.WithSource>
void setupPoiFeature(T element, FeatureCollector.Feature output) {
String rawSubclass = element.subclass(); String rawSubclass = element.subclass();
if ("station".equals(rawSubclass) && "subway".equals(element.station())) { if ("station".equals(rawSubclass) && "subway".equals(element.station())) {
rawSubclass = "subway"; rawSubclass = "subway";

Wyświetl plik

@ -80,8 +80,9 @@ import org.slf4j.LoggerFactory;
* Defines the logic for generating map elements for roads, shipways, railroads, and paths in the {@code transportation} * Defines the logic for generating map elements for roads, shipways, railroads, and paths in the {@code transportation}
* layer from source features. * layer from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/transportation">OpenMapTiles * This class is ported to Java from
* transportation sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/transportation">OpenMapTiles transportation
* sql files</a>.
*/ */
public class Transportation implements public class Transportation implements
OpenMapTilesSchema.Transportation, OpenMapTilesSchema.Transportation,
@ -214,7 +215,7 @@ public class Transportation implements
private static String railwayClass(String value) { private static String railwayClass(String value) {
return value == null ? null : return value == null ? null :
RAILWAY_RAIL_VALUES.contains(value) ? "rail" : RAILWAY_RAIL_VALUES.contains(value) ? "rail" :
RAILWAY_TRANSIT_VALUES.contains(value) ? "transit" : null; RAILWAY_TRANSIT_VALUES.contains(value) ? "transit" : null;
} }
static String highwayClass(String highway, String publicTransport, String construction, String manMade) { static String highwayClass(String highway, String publicTransport, String construction, String manMade) {
@ -320,8 +321,8 @@ public class Transportation implements
Geometry wayGeometry = element.source().worldGeometry(); Geometry wayGeometry = element.source().worldGeometry();
if (greatBritain.intersects(wayGeometry)) { if (greatBritain.intersects(wayGeometry)) {
Transportation.RouteNetwork networkType = Transportation.RouteNetwork networkType =
"motorway".equals(element.highway()) ? Transportation.RouteNetwork.GB_MOTORWAY "motorway".equals(element.highway()) ? Transportation.RouteNetwork.GB_MOTORWAY :
: Transportation.RouteNetwork.GB_TRUNK; Transportation.RouteNetwork.GB_TRUNK;
String network = "motorway".equals(element.highway()) ? "omt-gb-motorway" : "omt-gb-trunk"; String network = "motorway".equals(element.highway()) ? "omt-gb-motorway" : "omt-gb-trunk";
result.add(new RouteRelation(refMatcher.group(), network, networkType, (byte) -1, result.add(new RouteRelation(refMatcher.group(), network, networkType, (byte) -1,
0)); 0));
@ -434,7 +435,7 @@ public class Transportation implements
private boolean isPierPolygon(Tables.OsmHighwayLinestring element) { private boolean isPierPolygon(Tables.OsmHighwayLinestring element) {
if ("pier".equals(element.manMade())) { if ("pier".equals(element.manMade())) {
try { try {
if (element.source().worldGeometry() instanceof LineString lineString && lineString.isClosed()) { if (element.source().worldGeometry()instanceof LineString lineString && lineString.isClosed()) {
// ignore this because it's a polygon // ignore this because it's a polygon
return true; return true;
} }

Wyświetl plik

@ -67,7 +67,8 @@ import java.util.function.Function;
* Defines the logic for generating map elements for road, shipway, rail, and path names in the {@code * Defines the logic for generating map elements for road, shipway, rail, and path names in the {@code
* transportation_name} layer from source features. * transportation_name} layer from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/transportation_name">OpenMapTiles * This class is ported to Java from
* <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/transportation_name">OpenMapTiles
* transportation_name sql files</a>. * transportation_name sql files</a>.
*/ */
public class TransportationName implements public class TransportationName implements
@ -222,7 +223,7 @@ public class TransportationName implements
int minzoom = FieldValues.CLASS_TRUNK.equals(baseClass) ? 8 : int minzoom = FieldValues.CLASS_TRUNK.equals(baseClass) ? 8 :
FieldValues.CLASS_MOTORWAY.equals(baseClass) ? 6 : FieldValues.CLASS_MOTORWAY.equals(baseClass) ? 6 :
isLink ? 13 : 12; // fallback - get from line minzoom, but floor at 12 isLink ? 13 : 12; // fallback - get from line minzoom, but floor at 12
// inherit min zoom threshold from visible road, and ensure we never show a label on a road that's not visible yet. // inherit min zoom threshold from visible road, and ensure we never show a label on a road that's not visible yet.
minzoom = Math.max(minzoom, transportation.getMinzoom(element, highwayClass)); minzoom = Math.max(minzoom, transportation.getMinzoom(element, highwayClass));
@ -235,8 +236,8 @@ public class TransportationName implements
.setAttr(Fields.REF, ref) .setAttr(Fields.REF, ref)
.setAttr(Fields.REF_LENGTH, ref != null ? ref.length() : null) .setAttr(Fields.REF_LENGTH, ref != null ? ref.length() : null)
.setAttr(Fields.NETWORK, .setAttr(Fields.NETWORK,
(relation != null && relation.networkType() != null) ? relation.networkType().name (relation != null && relation.networkType() != null) ? relation.networkType().name :
: !nullOrEmpty(ref) ? "road" : null) !nullOrEmpty(ref) ? "road" : null)
.setAttr(Fields.CLASS, highwayClass) .setAttr(Fields.CLASS, highwayClass)
.setAttr(Fields.SUBCLASS, highwaySubclass(highwayClass, null, highway)) .setAttr(Fields.SUBCLASS, highwaySubclass(highwayClass, null, highway))
.setMinPixelSize(0) .setMinPixelSize(0)
@ -314,7 +315,7 @@ public class TransportationName implements
Function<Map<String, Object>, Double> lengthLimitCalculator = Function<Map<String, Object>, Double> lengthLimitCalculator =
zoom >= 14 ? (p -> 0d) : zoom >= 14 ? (p -> 0d) :
minLength > 0 ? (p -> minLength) : minLength > 0 ? (p -> minLength) :
this::getMinLengthForName; this::getMinLengthForName;
var result = FeatureMerge.mergeLineStrings(items, lengthLimitCalculator, tolerance, BUFFER_SIZE); var result = FeatureMerge.mergeLineStrings(items, lengthLimitCalculator, tolerance, BUFFER_SIZE);
if (limitMerge) { if (limitMerge) {
// remove temp keys that were just used to improve line merging // remove temp keys that were just used to improve line merging

Wyświetl plik

@ -49,8 +49,8 @@ import com.onthegomap.planetiler.util.Translations;
/** /**
* Defines the logic for generating map elements for oceans and lakes in the {@code water} layer from source features. * Defines the logic for generating map elements for oceans and lakes in the {@code water} layer from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/water">OpenMapTiles * This class is ported to Java from
* water sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/water">OpenMapTiles water sql files</a>.
*/ */
public class Water implements public class Water implements
OpenMapTilesSchema.Water, OpenMapTilesSchema.Water,

Wyświetl plik

@ -61,8 +61,9 @@ import org.slf4j.LoggerFactory;
* Defines the logic for generating map elements for ocean and lake names in the {@code water_name} layer from source * Defines the logic for generating map elements for ocean and lake names in the {@code water_name} layer from source
* features. * features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/water_name">OpenMapTiles * This class is ported to Java from
* water_name sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/water_name">OpenMapTiles water_name sql
* files</a>.
*/ */
public class WaterName implements public class WaterName implements
OpenMapTilesSchema.WaterName, OpenMapTilesSchema.WaterName,

Wyświetl plik

@ -63,8 +63,9 @@ import java.util.Map;
/** /**
* Defines the logic for generating river map elements in the {@code waterway} layer from source features. * Defines the logic for generating river map elements in the {@code waterway} layer from source features.
* <p> * <p>
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/waterway">OpenMapTiles * This class is ported to Java from
* waterway sql files</a>. * <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/waterway">OpenMapTiles waterway sql
* files</a>.
*/ */
public class Waterway implements public class Waterway implements
OpenMapTilesSchema.Waterway, OpenMapTilesSchema.Waterway,

Wyświetl plik

@ -49,7 +49,8 @@ import java.util.stream.Stream;
* Utilities to extract common name fields (name, name_en, name_de, name:latin, name:nonlatin, name_int) that the * Utilities to extract common name fields (name, name_en, name_de, name:latin, name:nonlatin, name_int) that the
* OpenMapTiles schema uses across any map element with a name. * OpenMapTiles schema uses across any map element with a name.
* <p> * <p>
* Ported from <a href="https://github.com/openmaptiles/openmaptiles-tools/blob/master/sql/zzz_language.sql">openmaptiles-tools</a>. * Ported from
* <a href="https://github.com/openmaptiles/openmaptiles-tools/blob/master/sql/zzz_language.sql">openmaptiles-tools</a>.
*/ */
public class LanguageUtils { public class LanguageUtils {
@ -101,12 +102,12 @@ public class LanguageUtils {
* element should have, derived from name, int_name, name:en, and name:de tags on the input element. * element should have, derived from name, int_name, name:en, and name:de tags on the input element.
* *
* <ul> * <ul>
* <li>name is the original name value from the element</li> * <li>name is the original name value from the element</li>
* <li>name_en is the original name:en value from the element, or name if missing</li> * <li>name_en is the original name:en value from the element, or name if missing</li>
* <li>name_de is the original name:de value from the element, or name/ name_en if missing</li> * <li>name_de is the original name:de value from the element, or name/ name_en if missing</li>
* <li>name:latin is the first of name, int_name, or any name: attribute that contains only latin characters</li> * <li>name:latin is the first of name, int_name, or any name: attribute that contains only latin characters</li>
* <li>name:nonlatin is any nonlatin part of name if present</li> * <li>name:nonlatin is any nonlatin part of name if present</li>
* <li>name_int is the first of int_name name:en name:latin name</li> * <li>name_int is the first of int_name name:en name:latin name</li>
* </ul> * </ul>
*/ */
public static Map<String, Object> getNamesWithoutTranslations(Map<String, Object> tags) { public static Map<String, Object> getNamesWithoutTranslations(Map<String, Object> tags) {
@ -126,8 +127,8 @@ public class LanguageUtils {
String nameDe = string(tags.get("name:de")); String nameDe = string(tags.get("name:de"));
boolean isLatin = containsOnlyLatinCharacters(name); boolean isLatin = containsOnlyLatinCharacters(name);
String latin = isLatin ? name String latin = isLatin ? name :
: Stream.concat(Stream.of(nameEn, intName, nameDe), getAllNameTranslationsBesidesEnglishAndGerman(tags)) Stream.concat(Stream.of(nameEn, intName, nameDe), getAllNameTranslationsBesidesEnglishAndGerman(tags))
.filter(LanguageUtils::containsOnlyLatinCharacters) .filter(LanguageUtils::containsOnlyLatinCharacters)
.findFirst().orElse(null); .findFirst().orElse(null);
if (latin == null && translations != null && translations.getShouldTransliterate()) { if (latin == null && translations != null && translations.getShouldTransliterate()) {

Wyświetl plik

@ -61,8 +61,8 @@ public abstract class AbstractLayerTest {
if (vals[i - 1] > vals[i]) { if (vals[i - 1] > vals[i]) {
fail( fail(
Arrays.toString(vals) + Arrays.toString(vals) +
System.lineSeparator() + "element at " + (i - 1) + " (" + vals[i - 1] + ") is greater than element at " + i System.lineSeparator() + "element at " + (i - 1) + " (" + vals[i - 1] + ") is greater than element at " +
+ " (" + vals[i] + ")"); i + " (" + vals[i] + ")");
} }
} }
} }

Wyświetl plik

@ -414,60 +414,60 @@ public class BoundaryTest extends AbstractLayerTest {
// shared edge // shared edge
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature( assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
newLineString(0, 0, 0, 10), newLineString(0, 0, 0, 10),
Map.of(), Map.of(),
OSM_SOURCE, OSM_SOURCE,
null, null,
3, 3,
Stream.concat( Stream.concat(
profile.preprocessOsmRelation(country1).stream(), profile.preprocessOsmRelation(country1).stream(),
profile.preprocessOsmRelation(country2).stream() profile.preprocessOsmRelation(country2).stream()
).map(r -> new OsmReader.RelationMember<>("", r)).toList() ).map(r -> new OsmReader.RelationMember<>("", r)).toList()
) )
)); ));
// other 2 edges of country 1 // other 2 edges of country 1
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature( assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
newLineString(0, 0, 5, 10), newLineString(0, 0, 5, 10),
Map.of(), Map.of(),
OSM_SOURCE, OSM_SOURCE,
null, null,
4, 4,
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r)) profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
.toList() .toList()
) )
)); ));
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature( assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
newLineString(0, 10, 5, 10), newLineString(0, 10, 5, 10),
Map.of(), Map.of(),
OSM_SOURCE, OSM_SOURCE,
null, null,
4, 4,
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r)) profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
.toList() .toList()
) )
)); ));
// other 2 edges of country 2 // other 2 edges of country 2
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature( assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
newLineString(0, 0, -5, 10), newLineString(0, 0, -5, 10),
Map.of(), Map.of(),
OSM_SOURCE, OSM_SOURCE,
null, null,
4, 4,
profile.preprocessOsmRelation(country2).stream().map(r -> new OsmReader.RelationMember<>("", r)) profile.preprocessOsmRelation(country2).stream().map(r -> new OsmReader.RelationMember<>("", r))
.toList() .toList()
) )
)); ));
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature( assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
newLineString(0, 10, -5, 10), newLineString(0, 10, -5, 10),
Map.of(), Map.of(),
OSM_SOURCE, OSM_SOURCE,
null, null,
4, 4,
profile.preprocessOsmRelation(country2).stream().map(r -> new OsmReader.RelationMember<>("", r)) profile.preprocessOsmRelation(country2).stream().map(r -> new OsmReader.RelationMember<>("", r))
.toList() .toList()
) )
)); ));
List<FeatureCollector.Feature> features = new ArrayList<>(); List<FeatureCollector.Feature> features = new ArrayList<>();

Wyświetl plik

@ -203,7 +203,7 @@ public class LandcoverTest extends AbstractLayerTest {
throws GeometryException { throws GeometryException {
assertEquals(expected, assertEquals(expected,
profile.postProcessLayerFeatures("landcover", zoom, in).stream().map( profile.postProcessLayerFeatures("landcover", zoom, in).stream().map(
VectorTile.Feature::attrs) VectorTile.Feature::attrs)
.toList()); .toList());
} }
} }

Wyświetl plik

@ -44,9 +44,9 @@ public class LanduseTest extends AbstractLayerTest {
"_minzoom", 9, "_minzoom", 9,
"_maxzoom", 14 "_maxzoom", 14
)), process(polygonFeature(Map.of( )), process(polygonFeature(Map.of(
"landuse", "railway", "landuse", "railway",
"amenity", "school" "amenity", "school"
)))); ))));
assertFeatures(13, List.of(Map.of("_layer", "poi"), Map.of( assertFeatures(13, List.of(Map.of("_layer", "poi"), Map.of(
"_layer", "landuse", "_layer", "landuse",
"class", "school", "class", "school",
@ -66,8 +66,8 @@ public class LanduseTest extends AbstractLayerTest {
"_layer", "landuse", "_layer", "landuse",
"class", "cemetery" "class", "cemetery"
)), process(polygonFeature(Map.of( )), process(polygonFeature(Map.of(
"amenity", "grave_yard" "amenity", "grave_yard"
)))); ))));
} }
@Test @Test

Wyświetl plik

@ -24,7 +24,7 @@ public class ParkTest extends AbstractLayerTest {
"name", "Grand Canyon National Park", "name", "Grand Canyon National Park",
"name_int", "Grand Canyon National Park", "name_int", "Grand Canyon National Park",
"name:latin", "Grand Canyon National Park", "name:latin", "Grand Canyon National Park",
// "name:es", "es name", // don't include all translations // "name:es", "es name", // don't include all translations
"_minzoom", 5, "_minzoom", 5,
"_maxzoom", 14 "_maxzoom", 14
)), process(polygonFeature(Map.of( )), process(polygonFeature(Map.of(

Wyświetl plik

@ -110,8 +110,8 @@ public class WaterTest extends AbstractLayerTest {
"_minzoom", 6, "_minzoom", 6,
"_maxzoom", 14 "_maxzoom", 14
)), process(polygonFeature(Map.of( )), process(polygonFeature(Map.of(
"leisure", "swimming_pool" "leisure", "swimming_pool"
)))); ))));
assertFeatures(14, List.of(), process(polygonFeature(Map.of( assertFeatures(14, List.of(), process(polygonFeature(Map.of(
"natural", "bay" "natural", "bay"
)))); ))));

Wyświetl plik

@ -17,7 +17,7 @@ import java.util.Random;
import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Geometry;
/** /**
* Performance tests for {@link MultiExpression}. Times how long a sample of elements from an OSM input file take to * Performance tests for {@link MultiExpression}. Times how long a sample of elements from an OSM input file take to
* match. * match.
*/ */
public class BasemapMapping { public class BasemapMapping {

Wyświetl plik

@ -22,13 +22,16 @@ import org.locationtech.jts.geom.Geometry;
* feature. * feature.
* <p> * <p>
* For example to add a polygon feature for a lake and a center label point with its name: * For example to add a polygon feature for a lake and a center label point with its name:
* <pre>{@code *
* <pre>
* {@code
* featureCollector.polygon("water") * featureCollector.polygon("water")
* .setAttr("class", "lake"); * .setAttr("class", "lake");
* featureCollector.centroid("water_name") * featureCollector.centroid("water_name")
* .setAttr("class", "lake") * .setAttr("class", "lake")
* .setAttr("name", element.getString("name")); * .setAttr("name", element.getString("name"));
* }</pre> * }
* </pre>
*/ */
public class FeatureCollector implements Iterable<FeatureCollector.Feature> { public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
@ -265,9 +268,8 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
* feature that appear later (higher sort key) in a layer. * feature that appear later (higher sort key) in a layer.
*/ */
public Feature setSortKey(int sortKey) { public Feature setSortKey(int sortKey) {
assert sortKey >= FeatureGroup.SORT_KEY_MIN && sortKey <= FeatureGroup.SORT_KEY_MAX : assert sortKey >= FeatureGroup.SORT_KEY_MIN && sortKey <= FeatureGroup.SORT_KEY_MAX : "Sort key " + sortKey +
"Sort key " + sortKey + " outside of allowed range [" + FeatureGroup.SORT_KEY_MIN + ", " " outside of allowed range [" + FeatureGroup.SORT_KEY_MIN + ", " + FeatureGroup.SORT_KEY_MAX + "]";
+ FeatureGroup.SORT_KEY_MAX + "]";
this.sortKey = sortKey; this.sortKey = sortKey;
return this; return this;
} }
@ -349,8 +351,8 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
/** /**
* Sets zoom-specific overrides to the number of pixels of detail to render outside the visible tile boundary. * Sets zoom-specific overrides to the number of pixels of detail to render outside the visible tile boundary.
* <p> * <p>
* If {@code buffer} is {@code null} or returns {@code null}, the buffer pixels will default to {@link * If {@code buffer} is {@code null} or returns {@code null}, the buffer pixels will default to
* #setBufferPixels(double)}. * {@link #setBufferPixels(double)}.
*/ */
public Feature setBufferPixelOverrides(ZoomFunction<Number> buffer) { public Feature setBufferPixelOverrides(ZoomFunction<Number> buffer) {
bufferPixelOverrides = buffer; bufferPixelOverrides = buffer;
@ -365,8 +367,8 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
* features to emit. * features to emit.
*/ */
public double getMinPixelSizeAtZoom(int zoom) { public double getMinPixelSizeAtZoom(int zoom) {
return zoom == config.maxzoom() ? minPixelSizeAtMaxZoom return zoom == config.maxzoom() ? minPixelSizeAtMaxZoom :
: ZoomFunction.applyAsDoubleOrElse(minPixelSize, zoom, defaultMinPixelSize); ZoomFunction.applyAsDoubleOrElse(minPixelSize, zoom, defaultMinPixelSize);
} }
/** /**
@ -400,8 +402,8 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
/** /**
* Overrides the default minimum pixel size at and below {@code zoom} with {@code minPixelSize}. * Overrides the default minimum pixel size at and below {@code zoom} with {@code minPixelSize}.
* <p> * <p>
* This replaces all previous zoom overrides that were set. To use multiple zoom-level thresholds, create a {@link * This replaces all previous zoom overrides that were set. To use multiple zoom-level thresholds, create a
* ZoomFunction} explicitly and pass it to {@link #setMinPixelSizeOverrides(ZoomFunction)}. * {@link ZoomFunction} explicitly and pass it to {@link #setMinPixelSizeOverrides(ZoomFunction)}.
*/ */
public Feature setMinPixelSizeBelowZoom(int zoom, double minPixelSize) { public Feature setMinPixelSizeBelowZoom(int zoom, double minPixelSize) {
if (zoom >= config.maxzoom()) { if (zoom >= config.maxzoom()) {
@ -429,7 +431,8 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
* Sets the minimum length of line features or square root of the minimum area of polygon features to emit at all * Sets the minimum length of line features or square root of the minimum area of polygon features to emit at all
* zoom levels, including the maximum zoom-level of the map. * zoom levels, including the maximum zoom-level of the map.
* <p> * <p>
* This replaces previous default values, but not overrides set with {@link #setMinPixelSizeOverrides(ZoomFunction)}. * This replaces previous default values, but not overrides set with
* {@link #setMinPixelSizeOverrides(ZoomFunction)}.
*/ */
public Feature setMinPixelSizeAtAllZooms(int minPixelSize) { public Feature setMinPixelSizeAtAllZooms(int minPixelSize) {
this.minPixelSizeAtMaxZoom = minPixelSize; this.minPixelSizeAtMaxZoom = minPixelSize;
@ -440,8 +443,8 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
* Returns the simplification tolerance for lines and polygons in tile pixels at {@code zoom}. * Returns the simplification tolerance for lines and polygons in tile pixels at {@code zoom}.
*/ */
public double getPixelToleranceAtZoom(int zoom) { public double getPixelToleranceAtZoom(int zoom) {
return zoom == config.maxzoom() ? pixelToleranceAtMaxZoom return zoom == config.maxzoom() ? pixelToleranceAtMaxZoom :
: ZoomFunction.applyAsDoubleOrElse(pixelTolerance, zoom, defaultPixelTolerance); ZoomFunction.applyAsDoubleOrElse(pixelTolerance, zoom, defaultPixelTolerance);
} }
/** /**
@ -497,8 +500,8 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
* Overrides the default simplification tolerance for lines and polygons in tile pixels at and below {@code zoom} * Overrides the default simplification tolerance for lines and polygons in tile pixels at and below {@code zoom}
* with {@code minPixelSize}. * with {@code minPixelSize}.
* <p> * <p>
* This replaces all previous zoom overrides that were set. To use multiple zoom-level thresholds, create a {@link * This replaces all previous zoom overrides that were set. To use multiple zoom-level thresholds, create a
* ZoomFunction} explicitly and pass it to {@link #setPixelToleranceOverrides(ZoomFunction)} * {@link ZoomFunction} explicitly and pass it to {@link #setPixelToleranceOverrides(ZoomFunction)}
*/ */
public Feature setPixelToleranceBelowZoom(int zoom, double tolerance) { public Feature setPixelToleranceBelowZoom(int zoom, double tolerance) {
if (zoom == config.maxzoom()) { if (zoom == config.maxzoom()) {
@ -519,9 +522,10 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
public double getPointLabelGridPixelSizeAtZoom(int zoom) { public double getPointLabelGridPixelSizeAtZoom(int zoom) {
double result = ZoomFunction.applyAsDoubleOrElse(labelGridPixelSize, zoom, DEFAULT_LABEL_GRID_SIZE); double result = ZoomFunction.applyAsDoubleOrElse(labelGridPixelSize, zoom, DEFAULT_LABEL_GRID_SIZE);
// TODO is this enough? what about a grid square that ends just before the start of the tile // TODO is this enough? what about a grid square that ends just before the start of the tile
assert result <= getBufferPixelsAtZoom(zoom) : assert result <= getBufferPixelsAtZoom(
"to avoid inconsistent rendering of the same point between adjacent tiles, buffer pixel size should be >= label grid size but in '%s' buffer pixel size=%f was greater than label grid size=%f".formatted( zoom) : "to avoid inconsistent rendering of the same point between adjacent tiles, buffer pixel size should be >= label grid size but in '%s' buffer pixel size=%f was greater than label grid size=%f"
getLayer(), getBufferPixelsAtZoom(zoom), result); .formatted(
getLayer(), getBufferPixelsAtZoom(zoom), result);
return result; return result;
} }
@ -550,7 +554,7 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
* @param labelGridSize a function that returns the size of the label grid to use at each zoom level. If function is * @param labelGridSize a function that returns the size of the label grid to use at each zoom level. If function is
* or returns null for a zoom-level, no label grid will be computed. * or returns null for a zoom-level, no label grid will be computed.
* @see <a href="https://github.com/mapbox/postgis-vt-util/blob/master/src/LabelGrid.sql">LabelGrid postgis * @see <a href="https://github.com/mapbox/postgis-vt-util/blob/master/src/LabelGrid.sql">LabelGrid postgis
* function</a> * function</a>
*/ */
public Feature setPointLabelGridPixelSize(ZoomFunction<Number> labelGridSize) { public Feature setPointLabelGridPixelSize(ZoomFunction<Number> labelGridSize) {
this.labelGridPixelSize = labelGridSize; this.labelGridPixelSize = labelGridSize;
@ -565,7 +569,7 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
* set for label grid size. To set multiple thresholds, use the other method directly. * set for label grid size. To set multiple thresholds, use the other method directly.
* *
* @see <a href="https://github.com/mapbox/postgis-vt-util/blob/master/src/LabelGrid.sql">LabelGrid postgis * @see <a href="https://github.com/mapbox/postgis-vt-util/blob/master/src/LabelGrid.sql">LabelGrid postgis
* function</a> * function</a>
*/ */
public Feature setPointLabelGridPixelSize(int maxzoom, double size) { public Feature setPointLabelGridPixelSize(int maxzoom, double size) {
return setPointLabelGridPixelSize(ZoomFunction.maxZoom(maxzoom, size)); return setPointLabelGridPixelSize(ZoomFunction.maxZoom(maxzoom, size));
@ -579,7 +583,7 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
* @param labelGridLimit a function that returns the size of the label grid to use at each zoom level. If function * @param labelGridLimit a function that returns the size of the label grid to use at each zoom level. If function
* is or returns null for a zoom-level, no label grid will be computed. * is or returns null for a zoom-level, no label grid will be computed.
* @see <a href="https://github.com/mapbox/postgis-vt-util/blob/master/src/LabelGrid.sql">LabelGrid postgis * @see <a href="https://github.com/mapbox/postgis-vt-util/blob/master/src/LabelGrid.sql">LabelGrid postgis
* function</a> * function</a>
*/ */
public Feature setPointLabelGridLimit(ZoomFunction<Number> labelGridLimit) { public Feature setPointLabelGridLimit(ZoomFunction<Number> labelGridLimit) {
this.labelGridLimit = labelGridLimit; this.labelGridLimit = labelGridLimit;
@ -590,9 +594,9 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
* Limits the density of points on an output tile at and below {@code maxzoom} by only emitting the {@code limit} * Limits the density of points on an output tile at and below {@code maxzoom} by only emitting the {@code limit}
* features with lowest sort-key in each square of a {@code size x size} pixel grid. * features with lowest sort-key in each square of a {@code size x size} pixel grid.
* <p> * <p>
* This is a thin wrapper around {@link #setPointLabelGridPixelSize(ZoomFunction)} and {@link * This is a thin wrapper around {@link #setPointLabelGridPixelSize(ZoomFunction)} and
* #setPointLabelGridLimit(ZoomFunction)}. It replaces any previous value set for label grid size or limit. To set * {@link #setPointLabelGridLimit(ZoomFunction)}. It replaces any previous value set for label grid size or limit.
* multiple thresholds, use the other methods directly. * To set multiple thresholds, use the other methods directly.
* <p> * <p>
* NOTE: the label grid is computed within each tile independently of its neighbors, so to ensure consistent limits * NOTE: the label grid is computed within each tile independently of its neighbors, so to ensure consistent limits
* and ranking of a point rendered in adjacent tiles, be sure to set the buffer pixel size to at least be larger * and ranking of a point rendered in adjacent tiles, be sure to set the buffer pixel size to at least be larger
@ -602,7 +606,7 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
* @param size the label grid size to use when computing hashes * @param size the label grid size to use when computing hashes
* @param limit the number of lowest-sort-key points to include in each square of the grid * @param limit the number of lowest-sort-key points to include in each square of the grid
* @see <a href="https://github.com/mapbox/postgis-vt-util/blob/master/src/LabelGrid.sql">LabelGrid postgis * @see <a href="https://github.com/mapbox/postgis-vt-util/blob/master/src/LabelGrid.sql">LabelGrid postgis
* function</a> * function</a>
*/ */
public Feature setPointLabelGridSizeAndLimit(int maxzoom, double size, int limit) { public Feature setPointLabelGridSizeAndLimit(int maxzoom, double size, int limit) {
return setPointLabelGridPixelSize(ZoomFunction.maxZoom(maxzoom, size)) return setPointLabelGridPixelSize(ZoomFunction.maxZoom(maxzoom, size))
@ -655,11 +659,11 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
} }
/** /**
* Sets the value for {@code key} attribute at or above {@code minzoom}. Below {@code minzoom} it will be ignored. * Sets the value for {@code key} attribute at or above {@code minzoom}. Below {@code minzoom} it will be ignored.
* <p> * <p>
* Replaces all previous value that has been for {@code key} at any zoom level. To have a value that changes at * Replaces all previous value that has been for {@code key} at any zoom level. To have a value that changes at
* multiple zoom level thresholds, call {@link #setAttr(String, Object)} with a manually-constructed {@link * multiple zoom level thresholds, call {@link #setAttr(String, Object)} with a manually-constructed
* ZoomFunction} value. * {@link ZoomFunction} value.
*/ */
public Feature setAttrWithMinzoom(String key, Object value, int minzoom) { public Feature setAttrWithMinzoom(String key, Object value, int minzoom) {
return setAttr(key, ZoomFunction.minZoom(minzoom, value)); return setAttr(key, ZoomFunction.minZoom(minzoom, value));

Wyświetl plik

@ -33,13 +33,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* A collection of utilities for merging features with the same attributes in a rendered tile from {@link * A collection of utilities for merging features with the same attributes in a rendered tile from
* Profile#postProcessLayerFeatures(String, int, List)} immediately before a tile is written to the output mbtiles * {@link Profile#postProcessLayerFeatures(String, int, List)} immediately before a tile is written to the output
* file. * mbtiles file.
* <p> * <p>
* Unlike postgis-based solutions that have a full view of all features after they are loaded into the databse, the * Unlike postgis-based solutions that have a full view of all features after they are loaded into the databse, the
* planetiler engine only sees a single input feature at a time while processing source features, then only has * planetiler engine only sees a single input feature at a time while processing source features, then only has
* visibility into multiple features when they are grouped into a tile immediately before emitting. This ends up being * visibility into multiple features when they are grouped into a tile immediately before emitting. This ends up being
* sufficient for most real-world use-cases but to do anything more that requires a view of multiple features * sufficient for most real-world use-cases but to do anything more that requires a view of multiple features
* <em>not</em> within the same tile, {@link Profile} implementations must store input features manually. * <em>not</em> within the same tile, {@link Profile} implementations must store input features manually.
*/ */
@ -53,8 +53,7 @@ public class FeatureMerge {
} }
/** Don't instantiate */ /** Don't instantiate */
private FeatureMerge() { private FeatureMerge() {}
}
/** /**
* Combines linestrings with the same set of attributes into a multilinestring where segments with touching endpoints * Combines linestrings with the same set of attributes into a multilinestring where segments with touching endpoints
@ -69,7 +68,7 @@ public class FeatureMerge {
* @param tolerance after merging, simplify linestrings using this pixel tolerance, or -1 to skip simplification step * @param tolerance after merging, simplify linestrings using this pixel tolerance, or -1 to skip simplification step
* @param buffer number of pixels outside the visible tile area to include detail for, or -1 to skip clipping step * @param buffer number of pixels outside the visible tile area to include detail for, or -1 to skip clipping step
* @return a new list containing all unaltered features in their original order, then each of the merged groups * @return a new list containing all unaltered features in their original order, then each of the merged groups
* ordered by the index of the first element in that group from the input list. * ordered by the index of the first element in that group from the input list.
*/ */
public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature> features, public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature> features,
double minLength, double tolerance, double buffer) { double minLength, double tolerance, double buffer) {
@ -78,7 +77,7 @@ public class FeatureMerge {
/** /**
* Merges linestrings with the same attributes like {@link #mergeLineStrings(List, double, double, double)} except * Merges linestrings with the same attributes like {@link #mergeLineStrings(List, double, double, double)} except
* with a dynamic length limit computed by {@code lengthLimitCalculator} for the attributes of each group. * with a dynamic length limit computed by {@code lengthLimitCalculator} for the attributes of each group.
*/ */
public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature> features, public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature> features,
Function<Map<String, Object>, Double> lengthLimitCalculator, double tolerance, double buffer) { Function<Map<String, Object>, Double> lengthLimitCalculator, double tolerance, double buffer) {
@ -186,7 +185,7 @@ public class FeatureMerge {
* @param features all features in a layer * @param features all features in a layer
* @param minArea minimum area in square tile pixels of polygons to emit * @param minArea minimum area in square tile pixels of polygons to emit
* @return a new list containing all unaltered features in their original order, then each of the merged groups * @return a new list containing all unaltered features in their original order, then each of the merged groups
* ordered by the index of the first element in that group from the input list. * ordered by the index of the first element in that group from the input list.
* @throws GeometryException if an error occurs encoding the combined geometry * @throws GeometryException if an error occurs encoding the combined geometry
*/ */
public static List<VectorTile.Feature> mergeOverlappingPolygons(List<VectorTile.Feature> features, double minArea) public static List<VectorTile.Feature> mergeOverlappingPolygons(List<VectorTile.Feature> features, double minArea)
@ -215,7 +214,7 @@ public class FeatureMerge {
* @param buffer the amount (in tile pixels) to expand then contract polygons by in order to combine * @param buffer the amount (in tile pixels) to expand then contract polygons by in order to combine
* almost-touching polygons * almost-touching polygons
* @return a new list containing all unaltered features in their original order, then each of the merged groups * @return a new list containing all unaltered features in their original order, then each of the merged groups
* ordered by the index of the first element in that group from the input list. * ordered by the index of the first element in that group from the input list.
* @throws GeometryException if an error occurs encoding the combined geometry * @throws GeometryException if an error occurs encoding the combined geometry
*/ */
public static List<VectorTile.Feature> mergeNearbyPolygons(List<VectorTile.Feature> features, double minArea, public static List<VectorTile.Feature> mergeNearbyPolygons(List<VectorTile.Feature> features, double minArea,

Wyświetl plik

@ -14,13 +14,13 @@ import java.util.function.Consumer;
* A framework for building complex {@link Profile Profiles} that need to be broken apart into multiple handlers (i.e. * A framework for building complex {@link Profile Profiles} that need to be broken apart into multiple handlers (i.e.
* one per layer). * one per layer).
* <p> * <p>
* Individual handlers added with {@link #registerHandler(Handler)} can listen on events by implementing these * Individual handlers added with {@link #registerHandler(Handler)} can listen on events by implementing these handlers:
* handlers:
* <ul> * <ul>
* <li>{@link OsmRelationPreprocessor} to process every OSM relation during first pass through OSM file</li> * <li>{@link OsmRelationPreprocessor} to process every OSM relation during first pass through OSM file</li>
* <li>{@link FeatureProcessor} to handle features from a particular source (added through {@link #registerSourceHandler(String, FeatureProcessor)})</li> * <li>{@link FeatureProcessor} to handle features from a particular source (added through
* <li>{@link FinishHandler} to be notified whenever we finish processing each source</li> * {@link #registerSourceHandler(String, FeatureProcessor)})</li>
* <li>{@link FeaturePostProcessor} to post-process features in a layer before rendering the output tile</li> * <li>{@link FinishHandler} to be notified whenever we finish processing each source</li>
* <li>{@link FeaturePostProcessor} to post-process features in a layer before rendering the output tile</li>
* </ul> * </ul>
* See {@code OpenMapTilesProfile} for a full implementation using this framework. * See {@code OpenMapTilesProfile} for a full implementation using this framework.
*/ */
@ -52,8 +52,8 @@ public abstract class ForwardingProfile implements Profile {
} }
/** /**
* Call {@code handler} for different events based on which interfaces {@code handler} implements: {@link * Call {@code handler} for different events based on which interfaces {@code handler} implements:
* OsmRelationPreprocessor}, {@link FinishHandler}, or {@link FeaturePostProcessor}. * {@link OsmRelationPreprocessor}, {@link FinishHandler}, or {@link FeaturePostProcessor}.
*/ */
public void registerHandler(Handler handler) { public void registerHandler(Handler handler) {
this.handlers.add(handler); this.handlers.add(handler);
@ -161,8 +161,7 @@ public abstract class ForwardingProfile implements Profile {
public interface Handler { public interface Handler {
/** Free any resources associated with this profile (i.e. shared data structures) */ /** Free any resources associated with this profile (i.e. shared data structures) */
default void release() { default void release() {}
}
} }
public interface HandlerForLayer extends Handler { public interface HandlerForLayer extends Handler {
@ -187,8 +186,7 @@ public abstract class ForwardingProfile implements Profile {
public interface OsmNodePreprocessor extends Handler { public interface OsmNodePreprocessor extends Handler {
/** /**
* Extracts information from an OSM node during pass 1 of the input OSM data that the profile may need during * Extracts information from an OSM node during pass 1 of the input OSM data that the profile may need during pass2.
* pass2.
* *
* @see Profile#preprocessOsmNode(OsmElement.Node) * @see Profile#preprocessOsmNode(OsmElement.Node)
*/ */

Wyświetl plik

@ -39,7 +39,9 @@ import org.slf4j.LoggerFactory;
* common use-cases. * common use-cases.
* <p> * <p>
* For example: * For example:
* <pre><code> *
* <pre>
* <code>
* public static void main(String[] args) { * public static void main(String[] args) {
* Planetiler.create(arguments) * Planetiler.create(arguments)
* .setProfile(new CustomProfile()) * .setProfile(new CustomProfile())
@ -48,7 +50,8 @@ import org.slf4j.LoggerFactory;
* .addOsmSource("osm", Path.of("source.osm.pbf")) * .addOsmSource("osm", Path.of("source.osm.pbf"))
* .setOutput("mbtiles", Path.of("output.mbtiles")) * .setOutput("mbtiles", Path.of("output.mbtiles"))
* .run(); * .run();
* }</code></pre> * }</code>
* </pre>
* <p> * <p>
* Each call to a builder API mutates the runner instance and returns it for more chaining. * Each call to a builder API mutates the runner instance and returns it for more chaining.
* <p> * <p>
@ -140,9 +143,9 @@ public class Planetiler {
* @param name string to use in stats and logs to identify this stage * @param name string to use in stats and logs to identify this stage
* @param defaultPath path to the input file to use if {@code name_path} argument is not set * @param defaultPath path to the input file to use if {@code name_path} argument is not set
* @param defaultUrl remote URL that the file to download if {@code download=true} argument is set and {@code * @param defaultUrl remote URL that the file to download if {@code download=true} argument is set and {@code
* name_url} argument is not set. As a shortcut, can use "geofabrik:monaco" or * name_url} argument is not set. As a shortcut, can use "geofabrik:monaco" or
* "geofabrik:australia" shorthand to find an extract by name from <a * "geofabrik:australia" shorthand to find an extract by name from
* href="https://download.geofabrik.de/">Geofabrik download site</a> or "aws:latest" to download * <a href="https://download.geofabrik.de/">Geofabrik download site</a> or "aws:latest" to download
* the latest {@code planet.osm.pbf} file from <a href="https://registry.opendata.aws/osm/">AWS * the latest {@code planet.osm.pbf} file from <a href="https://registry.opendata.aws/osm/">AWS
* Open Data Registry</a>. * Open Data Registry</a>.
* @return this runner instance for chaining * @return this runner instance for chaining
@ -180,8 +183,8 @@ public class Planetiler {
} }
/** /**
* Adds a new ESRI shapefile source that will be processed using a projection inferred from the shapefile when {@link * Adds a new ESRI shapefile source that will be processed using a projection inferred from the shapefile when
* #run()} is called. * {@link #run()} is called.
* <p> * <p>
* To override the location of the {@code shapefile} file, set {@code name_path=newpath.shp.zip} in the arguments. * To override the location of the {@code shapefile} file, set {@code name_path=newpath.shp.zip} in the arguments.
* *
@ -197,13 +200,12 @@ public class Planetiler {
} }
/** /**
* Adds a new ESRI shapefile source that will be processed using an explicit projection when {@link #run()} is * Adds a new ESRI shapefile source that will be processed using an explicit projection when {@link #run()} is called.
* called.
* <p> * <p>
* To override the location of the {@code shapefile} file, set {@code name_path=newpath.shp.zip} in the arguments. * To override the location of the {@code shapefile} file, set {@code name_path=newpath.shp.zip} in the arguments.
* *
* @param projection the Coordinate Reference System authority code to use, parsed with {@link * @param projection the Coordinate Reference System authority code to use, parsed with
* org.geotools.referencing.CRS#decode(String)} * {@link org.geotools.referencing.CRS#decode(String)}
* @param name string to use in stats and logs to identify this stage * @param name string to use in stats and logs to identify this stage
* @param defaultPath path to the input file to use if {@code name_path} key is not set through arguments. Can be a * @param defaultPath path to the input file to use if {@code name_path} key is not set through arguments. Can be a
* {@code .shp} file with other shapefile components in the same directory, or a {@code .zip} file * {@code .shp} file with other shapefile components in the same directory, or a {@code .zip} file
@ -216,8 +218,8 @@ public class Planetiler {
} }
/** /**
* Adds a new ESRI shapefile source that will be processed with a projection inferred from the shapefile when {@link * Adds a new ESRI shapefile source that will be processed with a projection inferred from the shapefile when
* #run()} is called. * {@link #run()} is called.
* <p> * <p>
* If the file does not exist and {@code download=true} argument is set, then the file will first be downloaded from * If the file does not exist and {@code download=true} argument is set, then the file will first be downloaded from
* {@code defaultUrl}. * {@code defaultUrl}.
@ -248,8 +250,8 @@ public class Planetiler {
* To override the location of the {@code shapefile} file, set {@code name_path=newpath.shp.zip} in the arguments and * To override the location of the {@code shapefile} file, set {@code name_path=newpath.shp.zip} in the arguments and
* to override the download URL set {@code name_url=http://url/of/shapefile.zip}. * to override the download URL set {@code name_url=http://url/of/shapefile.zip}.
* *
* @param projection the Coordinate Reference System authority code to use, parsed with {@link * @param projection the Coordinate Reference System authority code to use, parsed with
* org.geotools.referencing.CRS#decode(String)} * {@link org.geotools.referencing.CRS#decode(String)}
* @param name string to use in stats and logs to identify this stage * @param name string to use in stats and logs to identify this stage
* @param defaultPath path to the input file to use if {@code name_path} key is not set through arguments. Can be a * @param defaultPath path to the input file to use if {@code name_path} key is not set through arguments. Can be a
* {@code .shp} file with other shapefile components in the same directory, or a {@code .zip} file * {@code .shp} file with other shapefile components in the same directory, or a {@code .zip} file
@ -332,8 +334,8 @@ public class Planetiler {
} }
/** /**
* Updates {@link #translations()} to use name translations fetched from wikidata based on the <a * Updates {@link #translations()} to use name translations fetched from wikidata based on the
* href="https://www.wikidata.org/wiki/Wikidata:OpenStreetMap">wikidata tag</a> on OSM elements. * <a href="https://www.wikidata.org/wiki/Wikidata:OpenStreetMap">wikidata tag</a> on OSM elements.
* <p> * <p>
* When either {@code only_fetch_wikidata} or {@code fetch_wikidata} arguments are set to true, this downloads * When either {@code only_fetch_wikidata} or {@code fetch_wikidata} arguments are set to true, this downloads
* translations for every OSM element that the profile cares about and stores them to {@code defaultWikidataCache} (or * translations for every OSM element that the profile cares about and stores them to {@code defaultWikidataCache} (or
@ -393,8 +395,7 @@ public class Planetiler {
} }
/** /**
* Sets the location of the output {@code .mbtiles} file to write rendered tiles to. Fails if the file already * Sets the location of the output {@code .mbtiles} file to write rendered tiles to. Fails if the file already exists.
* exists.
* <p> * <p>
* To override the location of the file, set {@code argument=newpath.mbtiles} in the arguments. * To override the location of the file, set {@code argument=newpath.mbtiles} in the arguments.
* *
@ -570,9 +571,8 @@ public class Planetiler {
if (available < requested) { if (available < requested) {
var format = Format.defaultInstance(); var format = Format.defaultInstance();
String warning = String warning =
"Planetiler needs ~" + format.storage(requested) + " on " + fs + " during " + phase "Planetiler needs ~" + format.storage(requested) + " on " + fs + " during " + phase +
+ " phase, which only has " " phase, which only has " + format.storage(available) + " available";
+ format.storage(available) + " available";
if (config.force() || requested < available * 1.25) { if (config.force() || requested < available * 1.25) {
LOGGER.warn(warning + ", may fail."); LOGGER.warn(warning + ", may fail.");
} else { } else {
@ -592,9 +592,9 @@ public class Planetiler {
if (jvmMemory < requested) { if (jvmMemory < requested) {
String warning = String warning =
"Planetiler needs ~" + format.storage(requested) + " memory for the JVM, but only " "Planetiler needs ~" + format.storage(requested) + " memory for the JVM, but only " +
+ format.storage(jvmMemory) + " is available, try setting -Xmx=" + format.storage(requested).toLowerCase( format.storage(jvmMemory) + " is available, try setting -Xmx=" + format.storage(requested).toLowerCase(
Locale.ROOT); Locale.ROOT);
if (config.force() || requested < jvmMemory * 1.25) { if (config.force() || requested < jvmMemory * 1.25) {
LOGGER.warn(warning + ", may fail."); LOGGER.warn(warning + ", may fail.");
} else { } else {

Wyświetl plik

@ -14,17 +14,18 @@ import java.util.function.Consumer;
* <p> * <p>
* This includes: * This includes:
* <ul> * <ul>
* <li>How source features (OSM elements, shapefile elements, etc.) map to output features and their tags</li> * <li>How source features (OSM elements, shapefile elements, etc.) map to output features and their tags</li>
* <li>How vector tile features in an output tile should be post-processed (see {@link FeatureMerge})</li> * <li>How vector tile features in an output tile should be post-processed (see {@link FeatureMerge})</li>
* <li>What attributes to include in the mbtiles metadata output (see {@link Mbtiles})</li> * <li>What attributes to include in the mbtiles metadata output (see {@link Mbtiles})</li>
* <li>Whether {@link Wikidata} class should fetch wikidata translations for an OSM element</li> * <li>Whether {@link Wikidata} class should fetch wikidata translations for an OSM element</li>
* </ul> * </ul>
* <p> * <p>
* {@link Profile#processFeature(SourceFeature, FeatureCollector)} only handles a single element at a time. To "join" * {@link Profile#processFeature(SourceFeature, FeatureCollector)} only handles a single element at a time. To "join"
* elements across or within sources, implementations can store data in instance fields and wait to process them until * elements across or within sources, implementations can store data in instance fields and wait to process them until
* an element is encountered in a later source, or the {@link Profile#finish(String, FeatureCollector.Factory, Consumer)} * an element is encountered in a later source, or the
* method is called for a source. All methods may be called concurrently by multiple threads, so implementations must be * {@link Profile#finish(String, FeatureCollector.Factory, Consumer)} method is called for a source. All methods may be
* careful to ensure access to instance fields is thread-safe. * called concurrently by multiple threads, so implementations must be careful to ensure access to instance fields is
* thread-safe.
* <p> * <p>
* For complex profiles, {@link ForwardingProfile} provides a framework for splitting the logic up into several handlers * For complex profiles, {@link ForwardingProfile} provides a framework for splitting the logic up into several handlers
* (i.e. one per layer) and forwarding each element/event to the handlers that care about it. * (i.e. one per layer) and forwarding each element/event to the handlers that care about it.
@ -40,8 +41,7 @@ public interface Profile {
* *
* @param node the OSM node * @param node the OSM node
*/ */
default void preprocessOsmNode(OsmElement.Node node) { default void preprocessOsmNode(OsmElement.Node node) {}
}
/** /**
* Allows profile to extract any information it needs from a {@link OsmElement.Way} during the first pass through OSM * Allows profile to extract any information it needs from a {@link OsmElement.Way} during the first pass through OSM
@ -51,8 +51,7 @@ public interface Profile {
* *
* @param way the OSM way * @param way the OSM way
*/ */
default void preprocessOsmWay(OsmElement.Way way) { default void preprocessOsmWay(OsmElement.Way way) {}
}
/** /**
* Extracts information from <a href="https://wiki.openstreetmap.org/wiki/Relation">OSM relations</a> that will be * Extracts information from <a href="https://wiki.openstreetmap.org/wiki/Relation">OSM relations</a> that will be
@ -63,8 +62,8 @@ public interface Profile {
* The default implementation returns {@code null} to ignore all relations * The default implementation returns {@code null} to ignore all relations
* *
* @param relation the OSM relation * @param relation the OSM relation
* @return a list of relation info instances with information extracted from the relation to pass to {@link * @return a list of relation info instances with information extracted from the relation to pass to
* #processFeature(SourceFeature, FeatureCollector)}, or {@code null} to ignore. * {@link #processFeature(SourceFeature, FeatureCollector)}, or {@code null} to ignore.
*/ */
default List<OsmRelationInfo> preprocessOsmRelation(OsmElement.Relation relation) { default List<OsmRelationInfo> preprocessOsmRelation(OsmElement.Relation relation) {
return null; return null;
@ -74,7 +73,7 @@ public interface Profile {
* Generates output features for any input feature that should appear in the map. * Generates output features for any input feature that should appear in the map.
* <p> * <p>
* Multiple threads may invoke this method concurrently for a single data source so implementations should ensure * Multiple threads may invoke this method concurrently for a single data source so implementations should ensure
* thread-safe access to any shared data structures. Separate data sources are processed sequentially. * thread-safe access to any shared data structures. Separate data sources are processed sequentially.
* <p> * <p>
* All OSM nodes are processed first, then ways, then relations. * All OSM nodes are processed first, then ways, then relations.
* *
@ -84,8 +83,7 @@ public interface Profile {
void processFeature(SourceFeature sourceFeature, FeatureCollector features); void processFeature(SourceFeature sourceFeature, FeatureCollector features);
/** Free any resources associated with this profile (i.e. shared data structures) */ /** Free any resources associated with this profile (i.e. shared data structures) */
default void release() { default void release() {}
}
/** /**
* Apply any post-processing to features in an output layer of a tile before writing it to the output file * Apply any post-processing to features in an output layer of a tile before writing it to the output file
@ -101,8 +99,8 @@ public interface Profile {
* @param layer the output layer name * @param layer the output layer name
* @param zoom zoom level of the tile * @param zoom zoom level of the tile
* @param items all the output features in this layer in this tile * @param items all the output features in this layer in this tile
* @return the new list of output features or {@code null} to not change anything. Set any elements of the list to * @return the new list of output features or {@code null} to not change anything. Set any elements of the list to
* {@code null} if they should be ignored. * {@code null} if they should be ignored.
* @throws GeometryException for any recoverable geometric operation failures - the framework will log the error, emit * @throws GeometryException for any recoverable geometric operation failures - the framework will log the error, emit
* the original input features, and continue processing other tiles * the original input features, and continue processing other tiles
*/ */
@ -131,7 +129,7 @@ public interface Profile {
* Returns the attribution of the generated tileset to put into {@link Mbtiles} metadata * Returns the attribution of the generated tileset to put into {@link Mbtiles} metadata
* *
* @see <a href="https://www.openstreetmap.org/copyright">https://www.openstreetmap.org/copyright</a> for attribution * @see <a href="https://www.openstreetmap.org/copyright">https://www.openstreetmap.org/copyright</a> for attribution
* requirements of any map using OpenStreetMap data * requirements of any map using OpenStreetMap data
* @see <a href="https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md#metadata">MBTiles specification</a> * @see <a href="https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md#metadata">MBTiles specification</a>
*/ */
default String attribution() { default String attribution() {
@ -179,8 +177,7 @@ public interface Profile {
* @param next a consumer to pass finished map features to * @param next a consumer to pass finished map features to
*/ */
default void finish(String sourceName, FeatureCollector.Factory featureCollectors, default void finish(String sourceName, FeatureCollector.Factory featureCollectors,
Consumer<FeatureCollector.Feature> next) { Consumer<FeatureCollector.Feature> next) {}
}
/** /**
* Returns true if this profile will use any of the elements from an input source. * Returns true if this profile will use any of the elements from an input source.
@ -224,8 +221,7 @@ public interface Profile {
class NullProfile implements Profile { class NullProfile implements Profile {
@Override @Override
public void processFeature(SourceFeature sourceFeature, FeatureCollector features) { public void processFeature(SourceFeature sourceFeature, FeatureCollector features) {}
}
@Override @Override
public List<VectorTile.Feature> postProcessLayerFeatures(String layer, int zoom, public List<VectorTile.Feature> postProcessLayerFeatures(String layer, int zoom,

Wyświetl plik

@ -57,12 +57,12 @@ import vector_tile.VectorTileProto;
* Encodes a single output tile containing JTS {@link Geometry} features into the compact binary Mapbox Vector Tile * Encodes a single output tile containing JTS {@link Geometry} features into the compact binary Mapbox Vector Tile
* format. * format.
* <p> * <p>
* This class is copied from * This class is copied from <a href=
* <a href="https://github.com/ElectronicChartCentre/java-vector-tile/blob/master/src/main/java/no/ecc/vectortile/VectorTileEncoder.java">VectorTileEncoder.java</a> * "https://github.com/ElectronicChartCentre/java-vector-tile/blob/master/src/main/java/no/ecc/vectortile/VectorTileEncoder.java">VectorTileEncoder.java</a>
* and * and <a href=
* <a href="https://github.com/ElectronicChartCentre/java-vector-tile/blob/master/src/main/java/no/ecc/vectortile/VectorTileDecoder.java">VectorTileDecoder.java</a> * "https://github.com/ElectronicChartCentre/java-vector-tile/blob/master/src/main/java/no/ecc/vectortile/VectorTileDecoder.java">VectorTileDecoder.java</a>
* and modified to decouple geometry encoding from vector tile encoding so that encoded commands can be stored in the * and modified to decouple geometry encoding from vector tile encoding so that encoded commands can be stored in the
* sorted feature map prior to encoding vector tiles. The internals are also refactored to improve performance by using * sorted feature map prior to encoding vector tiles. The internals are also refactored to improve performance by using
* hppc primitive collections. * hppc primitive collections.
* *
* @see <a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1">Mapbox Vector Tile Specification</a> * @see <a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1">Mapbox Vector Tile Specification</a>
@ -389,8 +389,9 @@ public class VectorTile {
} }
/** /**
* Encodes a JTS geometry according to <a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#43-geometry-encoding">Geometry * Encodes a JTS geometry according to
* Encoding Specification</a>. * <a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#43-geometry-encoding">Geometry Encoding
* Specification</a>.
* *
* @param geometry the JTS geometry to encoded * @param geometry the JTS geometry to encoded
* @return the geometry type and command array for the encoded geometry * @return the geometry type and command array for the encoded geometry
@ -498,6 +499,7 @@ public class VectorTile {
MOVE_TO(1), MOVE_TO(1),
LINE_TO(2), LINE_TO(2),
CLOSE_PATH(7); CLOSE_PATH(7);
final int value; final int value;
Command(int value) { Command(int value) {
@ -506,8 +508,9 @@ public class VectorTile {
} }
/** /**
* A vector tile encoded as a list of commands according to the <a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#43-geometry-encoding">vector * A vector tile encoded as a list of commands according to the
* tile specification</a>. * <a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#43-geometry-encoding">vector tile
* specification</a>.
* <p> * <p>
* To encode extra precision in intermediate feature geometries, the geometry contained in {@code commands} is scaled * To encode extra precision in intermediate feature geometries, the geometry contained in {@code commands} is scaled
* to a tile extent of {@code EXTENT * 2^scale}, so when the {@code scale == 0} the extent is {@link #EXTENT} and when * to a tile extent of {@code EXTENT * 2^scale}, so when the {@code scale == 0} the extent is {@link #EXTENT} and when
@ -635,7 +638,7 @@ public class VectorTile {
/** /**
* Encodes a geometry as a sequence of integers according to the * Encodes a geometry as a sequence of integers according to the
* <a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#43-geometry-encoding">Geometry * Encoding * <a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#43-geometry-encoding">Geometry * Encoding
* Specification</a>. * Specification</a>.
*/ */
private static class CommandEncoder { private static class CommandEncoder {

Wyświetl plik

@ -90,10 +90,8 @@ public final class FeatureGroup implements Consumer<SortableFeature>, Iterable<F
* value contains grouping information. * value contains grouping information.
*/ */
static long encodeKey(int tile, byte layer, int sortKey, boolean hasGroup) { static long encodeKey(int tile, byte layer, int sortKey, boolean hasGroup) {
return ((long) tile << 32L) return ((long) tile << 32L) | ((long) (layer & 0xff) << 24L) | (((sortKey - SORT_KEY_MIN) & SORT_KEY_MASK) << 1L) |
| ((long) (layer & 0xff) << 24L) (hasGroup ? 1 : 0);
| (((sortKey - SORT_KEY_MIN) & SORT_KEY_MASK) << 1L)
| (hasGroup ? 1 : 0);
} }
static boolean extractHasGroupFromKey(long key) { static boolean extractHasGroupFromKey(long key) {

Wyświetl plik

@ -1,6 +1,5 @@
package com.onthegomap.planetiler.collection; package com.onthegomap.planetiler.collection;
import com.carrotsearch.hppc.IntObjectHashMap; import com.carrotsearch.hppc.IntObjectHashMap;
import com.carrotsearch.hppc.LongByteHashMap; import com.carrotsearch.hppc.LongByteHashMap;
import com.carrotsearch.hppc.LongByteMap; import com.carrotsearch.hppc.LongByteMap;

Wyświetl plik

@ -99,8 +99,7 @@ public interface LongLongMap extends Closeable, MemoryEstimator.HasEstimate, Dis
static LongLongMap noop() { static LongLongMap noop() {
return new LongLongMap() { return new LongLongMap() {
@Override @Override
public void put(long key, long value) { public void put(long key, long value) {}
}
@Override @Override
public long get(long key) { public long get(long key) {
@ -113,8 +112,7 @@ public interface LongLongMap extends Closeable, MemoryEstimator.HasEstimate, Dis
} }
@Override @Override
public void close() { public void close() {}
}
}; };
} }

Wyświetl plik

@ -97,10 +97,10 @@ public class Arguments {
* <p> * <p>
* Priority order: * Priority order:
* <ol> * <ol>
* <li>command-line arguments: {@code java ... key=value}</li> * <li>command-line arguments: {@code java ... key=value}</li>
* <li>jvm properties: {@code java -Dplanetiler.key=value ...}</li> * <li>jvm properties: {@code java -Dplanetiler.key=value ...}</li>
* <li>environmental variables: {@code PLANETILER_KEY=value java ...}</li> * <li>environmental variables: {@code PLANETILER_KEY=value java ...}</li>
* <li>in a config file from "config" argument from any of the above</li> * <li>in a config file from "config" argument from any of the above</li>
* </ol> * </ol>
* *
* @param args command-line args provide to main entrypoint method * @param args command-line args provide to main entrypoint method
@ -253,8 +253,8 @@ public class Arguments {
/** /**
* Returns a {@link Stats} implementation based on the arguments provided. * Returns a {@link Stats} implementation based on the arguments provided.
* <p> * <p>
* If {@code pushgateway} is set then it uses a stats implementation that pushes to prometheus through a <a * If {@code pushgateway} is set then it uses a stats implementation that pushes to prometheus through a
* href="https://github.com/prometheus/pushgateway">push gateway</a> every {@code pushgateway.interval} seconds. * <a href="https://github.com/prometheus/pushgateway">push gateway</a> every {@code pushgateway.interval} seconds.
* Otherwise, uses an in-memory stats implementation. * Otherwise, uses an in-memory stats implementation.
*/ */
public Stats getStats() { public Stats getStats() {

Wyświetl plik

@ -17,9 +17,12 @@ import java.util.stream.Stream;
* <p> * <p>
* Calling {@code toString()} on any expression will generate code that can be used to recreate an identical copy of the * Calling {@code toString()} on any expression will generate code that can be used to recreate an identical copy of the
* original expression, assuming that the generated code includes: * original expression, assuming that the generated code includes:
* <pre>{@code *
* <pre>
* {@code
* import static com.onthegomap.planetiler.expression.Expression.*; * import static com.onthegomap.planetiler.expression.Expression.*;
* }</pre> * }
* </pre>
*/ */
public interface Expression { public interface Expression {
@ -99,10 +102,10 @@ public interface Expression {
* <p> * <p>
* Allowed values: * Allowed values:
* <ul> * <ul>
* <li>"linestring"</li> * <li>"linestring"</li>
* <li>"point"</li> * <li>"point"</li>
* <li>"polygon"</li> * <li>"polygon"</li>
* <li>"relation_member"</li> * <li>"relation_member"</li>
* </ul> * </ul>
*/ */
static MatchType matchType(String type) { static MatchType matchType(String type) {
@ -190,7 +193,9 @@ public interface Expression {
return replace(a::equals, b); return replace(a::equals, b);
} }
/** Returns a copy of this expression where every nested instance matching {@code replace} is replaced with {@code b}. */ /**
* Returns a copy of this expression where every nested instance matching {@code replace} is replaced with {@code b}.
*/
default Expression replace(Predicate<Expression> replace, Expression b) { default Expression replace(Predicate<Expression> replace, Expression b) {
if (replace.test(this)) { if (replace.test(this)) {
return b; return b;

Wyświetl plik

@ -29,7 +29,7 @@ import java.util.function.Predicate;
* *
* @param <T> type of data value associated with each expression * @param <T> type of data value associated with each expression
*/ */
public record MultiExpression<T>(List<Entry<T>> expressions) { public record MultiExpression<T> (List<Entry<T>> expressions) {
public static <T> MultiExpression<T> of(List<Entry<T>> expressions) { public static <T> MultiExpression<T> of(List<Entry<T>> expressions) {
return new MultiExpression<>(expressions); return new MultiExpression<>(expressions);
@ -94,8 +94,8 @@ public record MultiExpression<T>(List<Entry<T>> expressions) {
if (expressions.isEmpty()) { if (expressions.isEmpty()) {
return new EmptyIndex<>(); return new EmptyIndex<>();
} }
boolean caresAboutGeometryType = expressions.stream().anyMatch(entry -> boolean caresAboutGeometryType =
entry.expression.contains(exp -> exp instanceof Expression.MatchType)); expressions.stream().anyMatch(entry -> entry.expression.contains(exp -> exp instanceof Expression.MatchType));
return caresAboutGeometryType ? new GeometryTypeIndex<>(this) : new KeyIndex<>(this); return caresAboutGeometryType ? new GeometryTypeIndex<>(this) : new KeyIndex<>(this);
} }
@ -308,13 +308,13 @@ public record MultiExpression<T>(List<Entry<T>> expressions) {
} }
/** An expression/value pair with unique ID to store whether we evaluated it yet. */ /** An expression/value pair with unique ID to store whether we evaluated it yet. */
private record EntryWithId<T>(T result, Expression expression, int id) {} private record EntryWithId<T> (T result, Expression expression, int id) {}
/** /**
* An {@code expression} to evaluate on input elements and {@code result} value to return when the element matches. * An {@code expression} to evaluate on input elements and {@code result} value to return when the element matches.
*/ */
public record Entry<T>(T result, Expression expression) {} public record Entry<T> (T result, Expression expression) {}
/** The result when an expression matches, along with the input element tag {@code keys} that triggered the match. */ /** The result when an expression matches, along with the input element tag {@code keys} that triggered the match. */
public record Match<T>(T match, List<String> keys) {} public record Match<T> (T match, List<String> keys) {}
} }

Wyświetl plik

@ -22,7 +22,8 @@ import org.locationtech.jts.geom.util.GeometryTransformer;
* A utility to simplify geometries using Douglas Peucker simplification algorithm without any attempt to repair * A utility to simplify geometries using Douglas Peucker simplification algorithm without any attempt to repair
* geometries that become invalid due to simplification. * geometries that become invalid due to simplification.
* <p> * <p>
* This class is adapted from <a href="https://github.com/locationtech/jts/blob/master/modules/core/src/main/java/org/locationtech/jts/simplify/DouglasPeuckerSimplifier.java">org.locationtech.jts.simplify.DouglasPeuckerSimplifier</a> * This class is adapted from <a href=
* "https://github.com/locationtech/jts/blob/master/modules/core/src/main/java/org/locationtech/jts/simplify/DouglasPeuckerSimplifier.java">org.locationtech.jts.simplify.DouglasPeuckerSimplifier</a>
* with modifications to avoid collapsing small polygons since the subsequent area filter will remove them more * with modifications to avoid collapsing small polygons since the subsequent area filter will remove them more
* accurately and performance improvement to put the results in a {@link MutableCoordinateSequence} which uses a * accurately and performance improvement to put the results in a {@link MutableCoordinateSequence} which uses a
* primitive double array instead of allocating lots of {@link Coordinate} objects. * primitive double array instead of allocating lots of {@link Coordinate} objects.
@ -148,4 +149,3 @@ public class DouglasPeuckerSimplifier {
} }
} }
} }

Wyświetl plik

@ -90,12 +90,13 @@ public class GeoUtils {
* right is (1,1). * right is (1,1).
*/ */
public static final Envelope WORLD_BOUNDS = new Envelope(0, 1, 0, 1); public static final Envelope WORLD_BOUNDS = new Envelope(0, 1, 0, 1);
/** Bounds for the entire area of the planet that a web mercator projection covers in latitude/longitude coordinates. */ /**
* Bounds for the entire area of the planet that a web mercator projection covers in latitude/longitude coordinates.
*/
public static final Envelope WORLD_LAT_LON_BOUNDS = toLatLonBoundsBounds(WORLD_BOUNDS); public static final Envelope WORLD_LAT_LON_BOUNDS = toLatLonBoundsBounds(WORLD_BOUNDS);
// should not instantiate // should not instantiate
private GeoUtils() { private GeoUtils() {}
}
/** /**
* Returns a copy of {@code geom} transformed from latitude/longitude coordinates to web mercator where top-left * Returns a copy of {@code geom} transformed from latitude/longitude coordinates to web mercator where top-left
@ -191,16 +192,16 @@ public class GeoUtils {
} }
/** /**
* Returns the web mercator Y coordinate of the latitude/longitude encoded with {@link #encodeFlatLocation(double, * Returns the web mercator Y coordinate of the latitude/longitude encoded with
* double)}. * {@link #encodeFlatLocation(double, double)}.
*/ */
public static double decodeWorldY(long encoded) { public static double decodeWorldY(long encoded) {
return (((double) (encoded & LOWER_32_BIT_MASK)) / HALF_QUANTIZED_WORLD_SIZE) - 1; return (((double) (encoded & LOWER_32_BIT_MASK)) / HALF_QUANTIZED_WORLD_SIZE) - 1;
} }
/** /**
* Returns the web mercator X coordinate of the latitude/longitude encoded with {@link #encodeFlatLocation(double, * Returns the web mercator X coordinate of the latitude/longitude encoded with
* double)}. * {@link #encodeFlatLocation(double, double)}.
*/ */
public static double decodeWorldX(long encoded) { public static double decodeWorldX(long encoded) {
return (((double) (encoded >>> 32)) / HALF_QUANTIZED_WORLD_SIZE) - 1; return (((double) (encoded >>> 32)) / HALF_QUANTIZED_WORLD_SIZE) - 1;

Wyświetl plik

@ -21,10 +21,8 @@ public enum GeometryType {
} }
public static GeometryType valueOf(Geometry geom) { public static GeometryType valueOf(Geometry geom) {
return geom instanceof Puntal ? POINT return geom instanceof Puntal ? POINT : geom instanceof Lineal ? LINE : geom instanceof Polygonal ? POLYGON :
: geom instanceof Lineal ? LINE UNKNOWN;
: geom instanceof Polygonal ? POLYGON
: UNKNOWN;
} }
public static GeometryType valueOf(VectorTileProto.Tile.GeomType geomType) { public static GeometryType valueOf(VectorTileProto.Tile.GeomType geomType) {

Wyświetl plik

@ -21,12 +21,11 @@ import org.locationtech.jts.index.strtree.STRtree;
@ThreadSafe @ThreadSafe
public class PointIndex<T> { public class PointIndex<T> {
private record GeomWithData<T>(Coordinate coord, T data) {} private record GeomWithData<T> (Coordinate coord, T data) {}
private final STRtree index = new STRtree(); private final STRtree index = new STRtree();
private PointIndex() { private PointIndex() {}
}
public static <T> PointIndex<T> create() { public static <T> PointIndex<T> create() {
return new PointIndex<>(); return new PointIndex<>();

Wyświetl plik

@ -19,12 +19,11 @@ import org.locationtech.jts.index.strtree.STRtree;
@ThreadSafe @ThreadSafe
public class PolygonIndex<T> { public class PolygonIndex<T> {
private record GeomWithData<T>(Polygon poly, T data) {} private record GeomWithData<T> (Polygon poly, T data) {}
private final STRtree index = new STRtree(); private final STRtree index = new STRtree();
private PolygonIndex() { private PolygonIndex() {}
}
public static <T> PolygonIndex<T> create() { public static <T> PolygonIndex<T> create() {
return new PolygonIndex<>(); return new PolygonIndex<>();
@ -78,7 +77,7 @@ public class PolygonIndex<T> {
List<?> items = index.query(point.getEnvelopeInternal()); List<?> items = index.query(point.getEnvelopeInternal());
// optimization: if there's only one then skip checking contains/distance // optimization: if there's only one then skip checking contains/distance
if (items.size() == 1) { if (items.size() == 1) {
if (items.get(0) instanceof GeomWithData<?> value) { if (items.get(0)instanceof GeomWithData<?> value) {
@SuppressWarnings("unchecked") T t = (T) value.data; @SuppressWarnings("unchecked") T t = (T) value.data;
return List.of(t); return List.of(t);
} }

Wyświetl plik

@ -38,8 +38,7 @@ import org.sqlite.SQLiteConfig;
/** /**
* Interface into an mbtiles sqlite file containing tiles and metadata about the tileset. * Interface into an mbtiles sqlite file containing tiles and metadata about the tileset.
* *
* @see <a href="https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md">MBTiles * @see <a href="https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md">MBTiles Specification</a>
* Specification</a>
*/ */
public final class Mbtiles implements Closeable { public final class Mbtiles implements Closeable {
@ -157,8 +156,8 @@ public final class Mbtiles implements Closeable {
return execute( return execute(
"create table " + METADATA_TABLE + " (" + METADATA_COL_NAME + " text, " + METADATA_COL_VALUE + " text);", "create table " + METADATA_TABLE + " (" + METADATA_COL_NAME + " text, " + METADATA_COL_VALUE + " text);",
"create unique index name on " + METADATA_TABLE + " (" + METADATA_COL_NAME + ");", "create unique index name on " + METADATA_TABLE + " (" + METADATA_COL_NAME + ");",
"create table " + TILES_TABLE + " (" + TILES_COL_Z + " integer, " + TILES_COL_X + " integer, " + TILES_COL_Y "create table " + TILES_TABLE + " (" + TILES_COL_Z + " integer, " + TILES_COL_X + " integer, " + TILES_COL_Y +
+ ", " + TILES_COL_DATA + " blob);" ", " + TILES_COL_DATA + " blob);"
); );
} }
@ -237,11 +236,10 @@ public final class Mbtiles implements Closeable {
* Data contained in the {@code json} row of the metadata table * Data contained in the {@code json} row of the metadata table
* *
* @see <a href="https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md#vector-tileset-metadata">MBtiles * @see <a href="https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md#vector-tileset-metadata">MBtiles
* schema</a> * schema</a>
*/ */
public record MetadataJson( public record MetadataJson(
@JsonProperty("vector_layers") @JsonProperty("vector_layers") List<VectorLayer> vectorLayers
List<VectorLayer> vectorLayers
) { ) {
public MetadataJson(VectorLayer... layers) { public MetadataJson(VectorLayer... layers) {
@ -265,9 +263,12 @@ public final class Mbtiles implements Closeable {
} }
public enum FieldType { public enum FieldType {
@JsonProperty("Number") NUMBER, @JsonProperty("Number")
@JsonProperty("Boolean") BOOLEAN, NUMBER,
@JsonProperty("String") STRING; @JsonProperty("Boolean")
BOOLEAN,
@JsonProperty("String")
STRING;
/** /**
* Per the spec: attributes whose type varies between features SHOULD be listed as "String" * Per the spec: attributes whose type varies between features SHOULD be listed as "String"
@ -352,7 +353,9 @@ public final class Mbtiles implements Closeable {
} }
} }
/** A high-throughput writer that accepts new tiles and queues up the writes to execute them in fewer large-batches. */ /**
* A high-throughput writer that accepts new tiles and queues up the writes to execute them in fewer large-batches.
*/
public class BatchedTileWriter implements AutoCloseable { public class BatchedTileWriter implements AutoCloseable {
// max number of parameters in a prepared statements is 999 // max number of parameters in a prepared statements is 999
@ -374,9 +377,8 @@ public final class Mbtiles implements Closeable {
} }
try { try {
return connection.prepareStatement( return connection.prepareStatement(
"INSERT INTO " + TILES_TABLE + " (" + TILES_COL_Z + "," + TILES_COL_X + "," + TILES_COL_Y + "," "INSERT INTO " + TILES_TABLE + " (" + TILES_COL_Z + "," + TILES_COL_X + "," + TILES_COL_Y + "," +
+ TILES_COL_DATA TILES_COL_DATA + ") VALUES " + String.join(", ", groups) + ";");
+ ") VALUES " + String.join(", ", groups) + ";");
} catch (SQLException throwables) { } catch (SQLException throwables) {
throw new IllegalStateException("Could not create prepared statement", throwables); throw new IllegalStateException("Could not create prepared statement", throwables);
} }
@ -443,8 +445,10 @@ public final class Mbtiles implements Closeable {
public Metadata setMetadata(String name, Object value) { public Metadata setMetadata(String name, Object value) {
if (value != null) { if (value != null) {
LOGGER.debug("Set mbtiles metadata: " + name + "=" + value); LOGGER.debug("Set mbtiles metadata: " + name + "=" + value);
try (PreparedStatement statement = connection.prepareStatement( try (
"INSERT INTO " + METADATA_TABLE + " (" + METADATA_COL_NAME + "," + METADATA_COL_VALUE + ") VALUES(?, ?);")) { PreparedStatement statement = connection.prepareStatement(
"INSERT INTO " + METADATA_TABLE + " (" + METADATA_COL_NAME + "," + METADATA_COL_VALUE + ") VALUES(?, ?);")
) {
statement.setString(1, name); statement.setString(1, name);
statement.setString(2, value.toString()); statement.setString(2, value.toString());
statement.execute(); statement.execute();

Wyświetl plik

@ -99,10 +99,10 @@ public class Verify {
/** /**
* Returns a verification result of a basic set of checks on an mbtiles file: * Returns a verification result of a basic set of checks on an mbtiles file:
* <ul> * <ul>
* <li>has a metadata and tiles table</li> * <li>has a metadata and tiles table</li>
* <li>has a name metadata attribute</li> * <li>has a name metadata attribute</li>
* <li>has at least one tile</li> * <li>has at least one tile</li>
* <li>all vector tile geometries are valid</li> * <li>all vector tile geometries are valid</li>
* </ul> * </ul>
*/ */
public static Verify verify(Mbtiles mbtiles) { public static Verify verify(Mbtiles mbtiles) {

Wyświetl plik

@ -29,8 +29,9 @@ import org.opengis.referencing.operation.MathTransform;
* <p> * <p>
* Shapefile processing handled by geotools {@link ShapefileDataStore}. * Shapefile processing handled by geotools {@link ShapefileDataStore}.
* *
* @see <a href="https://www.esri.com/content/dam/esrisites/sitecore-archive/Files/Pdfs/library/whitepapers/pdfs/shapefile.pdf">ESRI * @see <a href=
* Shapefile Specification</a> * "https://www.esri.com/content/dam/esrisites/sitecore-archive/Files/Pdfs/library/whitepapers/pdfs/shapefile.pdf">ESRI
* Shapefile Specification</a>
*/ */
public class ShapefileReader extends SimpleReader implements Closeable { public class ShapefileReader extends SimpleReader implements Closeable {
@ -72,8 +73,8 @@ public class ShapefileReader extends SimpleReader implements Closeable {
* Renders map features for all elements from an ESRI Shapefile based on the mapping logic defined in {@code profile}. * Renders map features for all elements from an ESRI Shapefile based on the mapping logic defined in {@code profile}.
* Overrides the coordinate reference system defined in the shapefile. * Overrides the coordinate reference system defined in the shapefile.
* *
* @param sourceProjection code for the coordinate reference system of the input data, to be parsed by {@link * @param sourceProjection code for the coordinate reference system of the input data, to be parsed by
* CRS#decode(String)} * {@link CRS#decode(String)}
* @param sourceName string ID for this reader to use in logs and stats * @param sourceName string ID for this reader to use in logs and stats
* @param input path to the {@code .shp} file on disk, or a {@code .zip} file containing the shapefile * @param input path to the {@code .shp} file on disk, or a {@code .zip} file containing the shapefile
* components * components
@ -95,8 +96,7 @@ public class ShapefileReader extends SimpleReader implements Closeable {
* Infers the coordinate reference system from the shapefile. * Infers the coordinate reference system from the shapefile.
* *
* @param sourceName string ID for this reader to use in logs and stats * @param sourceName string ID for this reader to use in logs and stats
* @param input path to the {@code .shp} file on disk, or a {@code .zip} file containing the shapefile * @param input path to the {@code .shp} file on disk, or a {@code .zip} file containing the shapefile components
* components
* @param writer consumer for rendered features * @param writer consumer for rendered features
* @param config user-defined parameters controlling number of threads and log interval * @param config user-defined parameters controlling number of threads and log interval
* @param profile logic that defines what map features to emit for each source feature * @param profile logic that defines what map features to emit for each source feature

Wyświetl plik

@ -83,14 +83,14 @@ public class SimpleFeature extends SourceFeature {
return new SimpleFeature(latLonGeometry, null, tags, source, sourceLayer, id, relations) { return new SimpleFeature(latLonGeometry, null, tags, source, sourceLayer, id, relations) {
@Override @Override
public boolean canBePolygon() { public boolean canBePolygon() {
return latLonGeometry instanceof Polygonal || (latLonGeometry instanceof LineString line return latLonGeometry instanceof Polygonal || (latLonGeometry instanceof LineString line &&
&& OsmReader.canBePolygon(line.isClosed(), area, latLonGeometry.getNumPoints())); OsmReader.canBePolygon(line.isClosed(), area, latLonGeometry.getNumPoints()));
} }
@Override @Override
public boolean canBeLine() { public boolean canBeLine() {
return latLonGeometry instanceof MultiLineString || (latLonGeometry instanceof LineString line return latLonGeometry instanceof MultiLineString || (latLonGeometry instanceof LineString line &&
&& OsmReader.canBeLine(line.isClosed(), area, latLonGeometry.getNumPoints())); OsmReader.canBeLine(line.isClosed(), area, latLonGeometry.getNumPoints()));
} }
@Override @Override
@ -103,15 +103,14 @@ public class SimpleFeature extends SourceFeature {
@Override @Override
public Geometry latLonGeometry() { public Geometry latLonGeometry() {
return latLonGeometry != null ? latLonGeometry return latLonGeometry != null ? latLonGeometry : (latLonGeometry = GeoUtils.worldToLatLonCoords(worldGeometry));
: (latLonGeometry = GeoUtils.worldToLatLonCoords(worldGeometry));
} }
@Override @Override
public Geometry worldGeometry() { public Geometry worldGeometry() {
// we expect outer polygons to appear before inner ones, so process ones with larger areas first // we expect outer polygons to appear before inner ones, so process ones with larger areas first
return worldGeometry != null ? worldGeometry return worldGeometry != null ? worldGeometry :
: (worldGeometry = GeoUtils.sortPolygonsByAreaDescending(GeoUtils.latLonToWorldCoords(latLonGeometry))); (worldGeometry = GeoUtils.sortPolygonsByAreaDescending(GeoUtils.latLonToWorldCoords(latLonGeometry)));
} }
@Override @Override

Wyświetl plik

@ -19,11 +19,11 @@ import org.locationtech.jts.geom.Polygon;
/** /**
* Base class for input features read from a data source. * Base class for input features read from a data source.
* <p> * <p>
* Provides cached convenience methods with lazy initialization for geometric attributes derived from {@link * Provides cached convenience methods with lazy initialization for geometric attributes derived from
* #latLonGeometry()} and {@link #worldGeometry()} to avoid computing them if not needed, and recomputing them if needed * {@link #latLonGeometry()} and {@link #worldGeometry()} to avoid computing them if not needed, and recomputing them if
* by multiple features. * needed by multiple features.
* <p> * <p>
* All geometries except for {@link #latLonGeometry()} return elements in world web mercator coordinates where (0,0) is * All geometries except for {@link #latLonGeometry()} return elements in world web mercator coordinates where (0,0) is
* the northwest corner and (1,1) is the southeast corner of the planet. * the northwest corner and (1,1) is the southeast corner of the planet.
*/ */
public abstract class SourceFeature implements WithTags { public abstract class SourceFeature implements WithTags {
@ -46,7 +46,7 @@ public abstract class SourceFeature implements WithTags {
* Constructs a new input feature. * Constructs a new input feature.
* *
* @param tags string key/value pairs associated with this element * @param tags string key/value pairs associated with this element
* @param source source name that profile can use to distinguish between elements from different data sources * @param source source name that profile can use to distinguish between elements from different data sources
* @param sourceLayer layer name within {@code source} that profile can use to distinguish between different kinds * @param sourceLayer layer name within {@code source} that profile can use to distinguish between different kinds
* of elements in a given source. * of elements in a given source.
* @param relationInfos relations that this element is contained within * @param relationInfos relations that this element is contained within
@ -116,7 +116,7 @@ public abstract class SourceFeature implements WithTags {
return centroid != null ? centroid : (centroid = return centroid != null ? centroid : (centroid =
canBePolygon() ? polygon().getCentroid() : canBePolygon() ? polygon().getCentroid() :
canBeLine() ? line().getCentroid() : canBeLine() ? line().getCentroid() :
worldGeometry().getCentroid()); worldGeometry().getCentroid());
} }
/** Returns and caches {@link Geometry#getInteriorPoint()} of this geometry in world web mercator coordinates. */ /** Returns and caches {@link Geometry#getInteriorPoint()} of this geometry in world web mercator coordinates. */
@ -124,13 +124,13 @@ public abstract class SourceFeature implements WithTags {
return pointOnSurface != null ? pointOnSurface : (pointOnSurface = return pointOnSurface != null ? pointOnSurface : (pointOnSurface =
canBePolygon() ? polygon().getInteriorPoint() : canBePolygon() ? polygon().getInteriorPoint() :
canBeLine() ? line().getInteriorPoint() : canBeLine() ? line().getInteriorPoint() :
worldGeometry().getInteriorPoint()); worldGeometry().getInteriorPoint());
} }
private Geometry computeCentroidIfConvex() throws GeometryException { private Geometry computeCentroidIfConvex() throws GeometryException {
if (!canBePolygon()) { if (!canBePolygon()) {
return centroid(); return centroid();
} else if (polygon() instanceof Polygon poly && } else if (polygon()instanceof Polygon poly &&
poly.getNumInteriorRing() == 0 && poly.getNumInteriorRing() == 0 &&
GeoUtils.isConvex(poly.getExteriorRing())) { GeoUtils.isConvex(poly.getExteriorRing())) {
return centroid(); return centroid();
@ -216,7 +216,7 @@ public abstract class SourceFeature implements WithTags {
/** /**
* Returns this feature as a valid {@link Polygon} or {@link MultiPolygon} in world web mercator coordinates. * Returns this feature as a valid {@link Polygon} or {@link MultiPolygon} in world web mercator coordinates.
* <p> * <p>
* Validating and fixing invalid polygons can be expensive, so use only if necessary. Invalid polygons will also be * Validating and fixing invalid polygons can be expensive, so use only if necessary. Invalid polygons will also be
* fixed at render-time. * fixed at render-time.
* *
* @throws GeometryException if an error occurs constructing the geometry, or of this feature should not be * @throws GeometryException if an error occurs constructing the geometry, or of this feature should not be
@ -283,7 +283,7 @@ public abstract class SourceFeature implements WithTags {
* @param relationInfoClass class of the processed relation data * @param relationInfoClass class of the processed relation data
* @param <T> type of {@code relationInfoClass} * @param <T> type of {@code relationInfoClass}
* @return A list containing the OSM relation info along with the role that this element is tagged with in that * @return A list containing the OSM relation info along with the role that this element is tagged with in that
* relation * relation
*/ */
// TODO this should be in a specialized OSM subclass, not the generic superclass // TODO this should be in a specialized OSM subclass, not the generic superclass
public <T extends OsmRelationInfo> List<OsmReader.RelationMember<T>> relationInfo( public <T extends OsmRelationInfo> List<OsmReader.RelationMember<T>> relationInfo(
@ -295,8 +295,7 @@ public abstract class SourceFeature implements WithTags {
if (result == null) { if (result == null) {
result = new ArrayList<>(); result = new ArrayList<>();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked") OsmReader.RelationMember<T> casted = (OsmReader.RelationMember<T>) info;
OsmReader.RelationMember<T> casted = (OsmReader.RelationMember<T>) info;
result.add(casted); result.add(casted);
} }
} }

Wyświetl plik

@ -13,12 +13,11 @@ public interface OsmBlockSource extends Closeable {
void forEachBlock(Consumer<Block> consumer); void forEachBlock(Consumer<Block> consumer);
@Override @Override
default void close() { default void close() {}
}
/** /**
* An individual block of raw bytes from an osm.pbf file that can be decompressed/parsed with {@link * An individual block of raw bytes from an osm.pbf file that can be decompressed/parsed with
* #decodeElements()}. * {@link #decodeElements()}.
*/ */
interface Block { interface Block {

Wyświetl plik

@ -23,7 +23,9 @@ public interface OsmElement extends WithTags {
int cost(); int cost();
enum Type { enum Type {
NODE, WAY, RELATION NODE,
WAY,
RELATION
} }
/** An un-handled element read from the .osm.pbf file (i.e. file header). */ /** An un-handled element read from the .osm.pbf file (i.e. file header). */
@ -165,7 +167,9 @@ public interface OsmElement extends WithTags {
return 1 + tags.size() + members.size() * 3; return 1 + tags.size() + members.size() * 3;
} }
/** A node, way, or relation contained in a relation with an optional "role" to clarify the purpose of each member. */ /**
* A node, way, or relation contained in a relation with an optional "role" to clarify the purpose of each member.
*/
public record Member( public record Member(
Type type, Type type,
long ref, long ref,

Wyświetl plik

@ -162,15 +162,15 @@ public class OsmReader implements Closeable, MemoryEstimator.HasEstimate {
node.encodedLocation(); node.encodedLocation();
if (nodesDone) { if (nodesDone) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Input file must be sorted with nodes first, then ways, then relations. Encountered node " + node.id() "Input file must be sorted with nodes first, then ways, then relations. Encountered node " + node.id() +
+ " after a way or relation"); " after a way or relation");
} }
} else if (element instanceof OsmElement.Way way) { } else if (element instanceof OsmElement.Way way) {
nodesDone = true; nodesDone = true;
if (waysDone) { if (waysDone) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Input file must be sorted with nodes first, then ways, then relations. Encountered way " + way.id() "Input file must be sorted with nodes first, then ways, then relations. Encountered way " + way.id() +
+ " after a relation"); " after a relation");
} }
} else if (element instanceof OsmElement.Relation) { } else if (element instanceof OsmElement.Relation) {
nodesDone = waysDone = true; nodesDone = waysDone = true;
@ -519,7 +519,7 @@ public class OsmReader implements Closeable, MemoryEstimator.HasEstimate {
* @param role "role" of the relation member * @param role "role" of the relation member
* @param relation user-provided data about the relation from pass1 * @param relation user-provided data about the relation from pass1
*/ */
public record RelationMember<T extends OsmRelationInfo>(String role, T relation) {} public record RelationMember<T extends OsmRelationInfo> (String role, T relation) {}
/** Raw relation membership data that gets encoded/decoded into a long. */ /** Raw relation membership data that gets encoded/decoded into a long. */
private record RelationMembership(String role, long relationId) {} private record RelationMembership(String role, long relationId) {}

Wyświetl plik

@ -11,7 +11,7 @@ import org.openstreetmap.osmosis.osmbinary.Osmformat;
* This class is copied from Osmosis. * This class is copied from Osmosis.
* *
* @author Brett Henderson * @author Brett Henderson
* <p> * <p>
*/ */
public class PbfFieldDecoder { public class PbfFieldDecoder {

Wyświetl plik

@ -71,8 +71,8 @@ public class FeatureRenderer implements Consumer<FeatureCollector.Feature> {
renderPoint(feature, point.getCoordinates()); renderPoint(feature, point.getCoordinates());
} else if (geom instanceof MultiPoint points) { } else if (geom instanceof MultiPoint points) {
renderPoint(feature, points); renderPoint(feature, points);
} else if (geom instanceof Polygon || geom instanceof MultiPolygon || geom instanceof LineString } else if (geom instanceof Polygon || geom instanceof MultiPolygon || geom instanceof LineString ||
|| geom instanceof MultiLineString) { geom instanceof MultiLineString) {
renderLineOrPolygon(feature, geom); renderLineOrPolygon(feature, geom);
} else if (geom instanceof GeometryCollection collection) { } else if (geom instanceof GeometryCollection collection) {
for (int i = 0; i < collection.getNumGeometries(); i++) { for (int i = 0; i < collection.getNumGeometries(); i++) {

Wyświetl plik

@ -22,9 +22,9 @@ import org.locationtech.jts.geom.Polygon;
* <p> * <p>
* The {@code List<List<CoordinateSequence>>} format is: * The {@code List<List<CoordinateSequence>>} format is:
* <ul> * <ul>
* <li>For linestrings: {@code [[linestring], [linestring], ...]}</li> for each linestring in the collection * <li>For linestrings: {@code [[linestring], [linestring], ...]}</li> for each linestring in the collection
* <li>For polygons: {@code [[outer ring, inner ring, inner ring], [outer ring, inner ring, ...], ...]}</li> for each * <li>For polygons: {@code [[outer ring, inner ring, inner ring], [outer ring, inner ring, ...], ...]}</li> for each
* polygon in the multipolygon * polygon in the multipolygon
* </ul> * </ul>
*/ */
class GeometryCoordinateSequences { class GeometryCoordinateSequences {
@ -36,14 +36,13 @@ class GeometryCoordinateSequences {
* For {@link LineString LineStrings} that means all linestrings over a certain length. * For {@link LineString LineStrings} that means all linestrings over a certain length.
* <p> * <p>
* For {@link Polygon Polygons} that means all lists of [exterior, interior...] ring coordinate sequences where the * For {@link Polygon Polygons} that means all lists of [exterior, interior...] ring coordinate sequences where the
* ring is over a certain area. This utility also ensures that exterior and interior rings use counter-clockwise * ring is over a certain area. This utility also ensures that exterior and interior rings use counter-clockwise
* winding. * winding.
* *
* @param geom one or more linestings or polygons * @param geom one or more linestings or polygons
* @param minSize minimum length of linestrings, or minimum area of exterior/interior rings to include * @param minSize minimum length of linestrings, or minimum area of exterior/interior rings to include
* @return the coordinate sequences of the geometry * @return the coordinate sequences of the geometry
* @throws IllegalArgumentException if {@code geom} contains anything other than linestrings or polygons (i.e. * @throws IllegalArgumentException if {@code geom} contains anything other than linestrings or polygons (i.e. points)
* points)
*/ */
static List<List<CoordinateSequence>> extractGroups(Geometry geom, double minSize) { static List<List<CoordinateSequence>> extractGroups(Geometry geom, double minSize) {
List<List<CoordinateSequence>> result = new ArrayList<>(); List<List<CoordinateSequence>> result = new ArrayList<>();

Wyświetl plik

@ -200,7 +200,9 @@ class TiledGeometry {
out.addPoint(x, ay + (by - ay) * t); out.addPoint(x, ay + (by - ay) * t);
} }
/** Adds a new point to {@code out} where the line segment from (ax,ay) to (bx,by) crosses a horizontal line at y=y. */ /**
* Adds a new point to {@code out} where the line segment from (ax,ay) to (bx,by) crosses a horizontal line at y=y.
*/
private static void intersectY(MutableCoordinateSequence out, double ax, double ay, double bx, double by, double y) { private static void intersectY(MutableCoordinateSequence out, double ax, double ay, double bx, double by, double y) {
double t = (y - ay) / (by - ay); double t = (y - ay) / (by - ay);
out.addPoint(ax + (bx - ax) * t, y); out.addPoint(ax + (bx - ax) * t, y);
@ -221,15 +223,15 @@ class TiledGeometry {
/** /**
* Slices a geometry into tiles and stores in member fields for a single "copy" of the world. * Slices a geometry into tiles and stores in member fields for a single "copy" of the world.
* <p> * <p>
* Instead of handling content outside -180 to 180 degrees longitude, return {@link Direction#LEFT} or {@link * Instead of handling content outside -180 to 180 degrees longitude, return {@link Direction#LEFT} or
* Direction#RIGHT} to indicate whether this method should be called again with a different {@code xOffset} to process * {@link Direction#RIGHT} to indicate whether this method should be called again with a different {@code xOffset} to
* wrapped content. * process wrapped content.
* *
* @param groups the geometry * @param groups the geometry
* @param xOffset offset to apply to each X coordinate (-2^z handles content that wraps too far east and 2^z handles * @param xOffset offset to apply to each X coordinate (-2^z handles content that wraps too far east and 2^z handles
* content that wraps too far west) * content that wraps too far west)
* @return {@link Direction#LEFT} if there is more content to the west and {@link Direction#RIGHT} if there is more * @return {@link Direction#LEFT} if there is more content to the west and {@link Direction#RIGHT} if there is more
* content to the east. * content to the east.
*/ */
private EnumSet<Direction> sliceWorldCopy(List<List<CoordinateSequence>> groups, int xOffset) { private EnumSet<Direction> sliceWorldCopy(List<List<CoordinateSequence>> groups, int xOffset) {
EnumSet<Direction> overflow = EnumSet.noneOf(Direction.class); EnumSet<Direction> overflow = EnumSet.noneOf(Direction.class);
@ -603,5 +605,8 @@ class TiledGeometry {
} }
} }
private enum Direction {RIGHT, LEFT} private enum Direction {
RIGHT,
LEFT
}
} }

Wyświetl plik

@ -51,8 +51,7 @@ public interface Counter {
*/ */
class SingleThreadCounter implements Readable { class SingleThreadCounter implements Readable {
private SingleThreadCounter() { private SingleThreadCounter() {}
}
private final AtomicLong counter = new AtomicLong(0); private final AtomicLong counter = new AtomicLong(0);
@ -75,8 +74,7 @@ public interface Counter {
*/ */
class MultiThreadCounter implements Readable { class MultiThreadCounter implements Readable {
private MultiThreadCounter() { private MultiThreadCounter() {}
}
// keep track of all counters that have been handed out to threads so far // keep track of all counters that have been handed out to threads so far
// and on read, add up the counts from each // and on read, add up the counts from each

Wyświetl plik

@ -37,7 +37,7 @@ public class ProcessInfo {
for (GarbageCollectorMXBean garbageCollectorMXBean : ManagementFactory.getGarbageCollectorMXBeans()) { for (GarbageCollectorMXBean garbageCollectorMXBean : ManagementFactory.getGarbageCollectorMXBeans()) {
if (garbageCollectorMXBean instanceof NotificationEmitter emitter) { if (garbageCollectorMXBean instanceof NotificationEmitter emitter) {
emitter.addNotificationListener((notification, handback) -> { emitter.addNotificationListener((notification, handback) -> {
if (notification.getUserData() instanceof CompositeData compositeData) { if (notification.getUserData()instanceof CompositeData compositeData) {
var info = GarbageCollectionNotificationInfo.from(compositeData); var info = GarbageCollectionNotificationInfo.from(compositeData);
GcInfo gcInfo = info.getGcInfo(); GcInfo gcInfo = info.getGcInfo();
postGcMemoryUsage.set(gcInfo.getMemoryUsageAfterGc().entrySet().stream() postGcMemoryUsage.set(gcInfo.getMemoryUsageAfterGc().entrySet().stream()

Wyświetl plik

@ -9,12 +9,15 @@ import java.util.Optional;
* A utility for measuring the wall and CPU time that this JVM consumes between snapshots. * A utility for measuring the wall and CPU time that this JVM consumes between snapshots.
* <p> * <p>
* For example: * For example:
* <pre>{@code *
* <pre>
* {@code
* var start = ProcessTime.now(); * var start = ProcessTime.now();
* // do expensive work... * // do expensive work...
* var end - ProcessTime.now(); * var end - ProcessTime.now();
* LOGGER.log("Expensive work took " + end.minus(start)); * LOGGER.log("Expensive work took " + end.minus(start));
* }</pre> * }
* </pre>
*/ */
public record ProcessTime(Duration wall, Optional<Duration> cpu, Duration gc) { public record ProcessTime(Duration wall, Optional<Duration> cpu, Duration gc) {

Wyświetl plik

@ -166,8 +166,8 @@ public class ProgressLoggers {
last.set(valueNow); last.set(valueNow);
lastTime.set(now); lastTime.set(now);
String result = String result =
"[ " + formatter.apply(valueNow) + " " + padLeft(format.percent(1f * valueNow / total), 4) "[ " + formatter.apply(valueNow) + " " + padLeft(format.percent(1f * valueNow / total), 4) + " " +
+ " " + formatter.apply(valueDiff / timeDiff) + "/s ]"; formatter.apply(valueDiff / timeDiff) + "/s ]";
return (color && valueDiff > 0) ? green(result) : result; return (color && valueDiff > 0) ? green(result) : result;
})); }));
return this; return this;
@ -188,12 +188,9 @@ public class ProgressLoggers {
/** Adds the current number of items in a queue and the queue's size to the output. */ /** Adds the current number of items in a queue and the queue's size to the output. */
public ProgressLoggers addQueueStats(WorkQueue<?> queue) { public ProgressLoggers addQueueStats(WorkQueue<?> queue) {
loggers.add(new WorkerPipelineLogger(() -> loggers.add(new WorkerPipelineLogger(() -> " -> " + padLeft("(" +
" -> " + padLeft("(" + format.numeric(queue.getPending(), false) + "/" +
format.numeric(queue.getPending(), false) format.numeric(queue.getCapacity(), false) + ")", 9)
+ "/" +
format.numeric(queue.getCapacity(), false)
+ ")", 9)
)); ));
return this; return this;
} }

Wyświetl plik

@ -271,8 +271,8 @@ class PrometheusStats implements Stats {
} }
/** /**
* Reports stats on all in-memory objects sizes being monitored through {@link #monitorInMemoryObject(String, * Reports stats on all in-memory objects sizes being monitored through
* MemoryEstimator.HasEstimate)}. * {@link #monitorInMemoryObject(String, MemoryEstimator.HasEstimate)}.
*/ */
private class HeapObjectSizeCollector extends Collector { private class HeapObjectSizeCollector extends Collector {

Wyświetl plik

@ -17,9 +17,9 @@ import org.slf4j.LoggerFactory;
/** /**
* A utility that collects and reports more detailed statistics about the JVM and running tasks than logs can convey. * A utility that collects and reports more detailed statistics about the JVM and running tasks than logs can convey.
* <p> * <p>
* {@link #inMemory()} stores basic stats in-memory to report at the end of the job and {@link * {@link #inMemory()} stores basic stats in-memory to report at the end of the job and
* #prometheusPushGateway(String, String, Duration)} pushes stats at a regular interval to a <a * {@link #prometheusPushGateway(String, String, Duration)} pushes stats at a regular interval to a
* href="https://github.com/prometheus/pushgateway">prometheus push gateway</a>. * <a href="https://github.com/prometheus/pushgateway">prometheus push gateway</a>.
*/ */
public interface Stats extends AutoCloseable { public interface Stats extends AutoCloseable {
@ -29,8 +29,8 @@ public interface Stats extends AutoCloseable {
} }
/** /**
* Returns a new stat collector pushes stats at a regular interval to a <a href="https://github.com/prometheus/pushgateway">prometheus * Returns a new stat collector pushes stats at a regular interval to a
* push gateway</a> at {@code destination}. * <a href="https://github.com/prometheus/pushgateway">prometheus push gateway</a> at {@code destination}.
*/ */
static Stats prometheusPushGateway(String destination, String job, Duration interval) { static Stats prometheusPushGateway(String destination, String job, Duration interval) {
return PrometheusStats.createAndStartPushing(destination, job, interval); return PrometheusStats.createAndStartPushing(destination, job, interval);
@ -43,7 +43,7 @@ public interface Stats extends AutoCloseable {
default void printSummary() { default void printSummary() {
Format format = Format.defaultInstance(); Format format = Format.defaultInstance();
Logger LOGGER = LoggerFactory.getLogger(getClass()); Logger LOGGER = LoggerFactory.getLogger(getClass());
System.out.println(); LOGGER.info("");
LOGGER.info("-".repeat(40)); LOGGER.info("-".repeat(40));
timers().printSummary(); timers().printSummary();
LOGGER.info("-".repeat(40)); LOGGER.info("-".repeat(40));
@ -145,15 +145,13 @@ public interface Stats extends AutoCloseable {
class InMemory implements Stats { class InMemory implements Stats {
/** use {@link #inMemory()} */ /** use {@link #inMemory()} */
private InMemory() { private InMemory() {}
}
private final Timers timers = new Timers(); private final Timers timers = new Timers();
private final Map<String, Path> monitoredFiles = new ConcurrentSkipListMap<>(); private final Map<String, Path> monitoredFiles = new ConcurrentSkipListMap<>();
@Override @Override
public void wroteTile(int zoom, int bytes) { public void wroteTile(int zoom, int bytes) {}
}
@Override @Override
public Timers timers() { public Timers timers() {
@ -166,12 +164,10 @@ public interface Stats extends AutoCloseable {
} }
@Override @Override
public void monitorInMemoryObject(String name, MemoryEstimator.HasEstimate object) { public void monitorInMemoryObject(String name, MemoryEstimator.HasEstimate object) {}
}
@Override @Override
public void counter(String name, Supplier<Number> supplier) { public void counter(String name, Supplier<Number> supplier) {}
}
@Override @Override
public Counter.MultiThreadCounter longCounter(String name) { public Counter.MultiThreadCounter longCounter(String name) {
@ -184,24 +180,19 @@ public interface Stats extends AutoCloseable {
} }
@Override @Override
public void counter(String name, String label, Supplier<Map<String, Counter.Readable>> values) { public void counter(String name, String label, Supplier<Map<String, Counter.Readable>> values) {}
}
@Override @Override
public void processedElement(String elemType, String layer) { public void processedElement(String elemType, String layer) {}
}
@Override @Override
public void dataError(String errorCode) { public void dataError(String errorCode) {}
}
@Override @Override
public void gauge(String name, Supplier<Number> value) { public void gauge(String name, Supplier<Number> value) {}
}
@Override @Override
public void emittedFeatures(int z, String layer, int numFeatures) { public void emittedFeatures(int z, String layer, int numFeatures) {}
}
@Override @Override
public void close() { public void close() {

Wyświetl plik

@ -95,7 +95,7 @@ public class Timers {
Stage stage = new Stage(timer); Stage stage = new Stage(timer);
timers.put(name, stage); timers.put(name, stage);
Stage last = currentStage.getAndSet(stage); Stage last = currentStage.getAndSet(stage);
System.out.println(); LOGGER.info("");
LOGGER.info("Starting..."); LOGGER.info("Starting...");
return () -> { return () -> {
LOGGER.info("Finished in " + timers.get(name).timer.stop()); LOGGER.info("Finished in " + timers.get(name).timer.stop());

Wyświetl plik

@ -77,13 +77,11 @@ public class AwsOsm {
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
record IndexXml( record IndexXml(
@JacksonXmlProperty(localName = "Contents") @JacksonXmlProperty(localName = "Contents")
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlElementWrapper(useWrapping = false) List<ContentXml> contents
List<ContentXml> contents
) {} ) {}
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
record ContentXml( record ContentXml(
@JacksonXmlProperty(localName = "Key") @JacksonXmlProperty(localName = "Key") String key
String key
) {} ) {}
} }

Wyświetl plik

@ -46,20 +46,23 @@ import org.slf4j.LoggerFactory;
* changes. * changes.
* <p> * <p>
* For example: * For example:
* <pre>{@code *
* <pre>
* {@code
* Downloader.create(PlanetilerConfig.defaults()) * Downloader.create(PlanetilerConfig.defaults())
* .add("natural_earth", "http://url/of/natural_earth.zip", Path.of("natural_earth.zip")) * .add("natural_earth", "http://url/of/natural_earth.zip", Path.of("natural_earth.zip"))
* .add("osm", "http://url/of/file.osm.pbf", Path.of("file.osm.pbf")) * .add("osm", "http://url/of/file.osm.pbf", Path.of("file.osm.pbf"))
* .run(); * .run();
* }</pre> * }
* </pre>
* <p> * <p>
* As a shortcut to find the URL of a file to download from the <a href="https://download.geofabrik.de/">Geofabrik * As a shortcut to find the URL of a file to download from the <a href="https://download.geofabrik.de/">Geofabrik
* download site</a>, you can use "geofabrik:extract name" (i.e. "geofabrik:monaco" or "geofabrik:australia") to look up * download site</a>, you can use "geofabrik:extract name" (i.e. "geofabrik:monaco" or "geofabrik:australia") to look up
* a {@code .osm.pbf} download URL in the <a href="https://download.geofabrik.de/technical.html">Geofabrik JSON * a {@code .osm.pbf} download URL in the <a href="https://download.geofabrik.de/technical.html">Geofabrik JSON
* index</a>. * index</a>.
* <p> * <p>
* You can also use "aws:latest" to download the latest {@code planet.osm.pbf} file from the <a * You can also use "aws:latest" to download the latest {@code planet.osm.pbf} file from the
* href="https://registry.opendata.aws/osm/">AWS Open Data Registry</a>. * <a href="https://registry.opendata.aws/osm/">AWS Open Data Registry</a>.
*/ */
@SuppressWarnings("UnusedReturnValue") @SuppressWarnings("UnusedReturnValue")
public class Downloader { public class Downloader {
@ -198,9 +201,8 @@ public class Downloader {
LOGGER.info("Skipping " + resourceToDownload.id + ": " + resourceToDownload.output + " already up-to-date"); LOGGER.info("Skipping " + resourceToDownload.id + ": " + resourceToDownload.output + " already up-to-date");
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} else { } else {
String redirectInfo = metadata.canonicalUrl.equals(resourceToDownload.url) String redirectInfo = metadata.canonicalUrl.equals(resourceToDownload.url) ? "" :
? "" " (redirected to " + metadata.canonicalUrl + ")";
: " (redirected to " + metadata.canonicalUrl + ")";
LOGGER.info("Downloading " + resourceToDownload.url + redirectInfo + " to " + resourceToDownload.output); LOGGER.info("Downloading " + resourceToDownload.url + redirectInfo + " to " + resourceToDownload.output);
FileUtils.delete(resourceToDownload.output); FileUtils.delete(resourceToDownload.output);
FileUtils.createParentDirectories(resourceToDownload.output); FileUtils.createParentDirectories(resourceToDownload.output);
@ -237,8 +239,8 @@ public class Downloader {
if (totalPendingBytes > availableBytes) { if (totalPendingBytes > availableBytes) {
var format = Format.defaultInstance(); var format = Format.defaultInstance();
String warning = String warning =
"Attempting to download " + format.storage(totalPendingBytes) + " to " + fs + " which only has " "Attempting to download " + format.storage(totalPendingBytes) + " to " + fs + " which only has " +
+ format.storage(availableBytes) + " available"; format.storage(availableBytes) + " available";
if (config.force()) { if (config.force()) {
LOGGER.warn(warning + ", will probably fail."); LOGGER.warn(warning + ", will probably fail.");
} else { } else {
@ -254,9 +256,8 @@ public class Downloader {
if (redirects > MAX_REDIRECTS) { if (redirects > MAX_REDIRECTS) {
throw new IllegalStateException("Exceeded " + redirects + " redirects for " + url); throw new IllegalStateException("Exceeded " + redirects + " redirects for " + url);
} }
return httpHead(url).thenComposeAsync(response -> response.redirect.isPresent() return httpHead(url).thenComposeAsync(response -> response.redirect.isPresent() ?
? httpHeadFollowRedirects(response.redirect.get(), redirects + 1) httpHeadFollowRedirects(response.redirect.get(), redirects + 1) : CompletableFuture.completedFuture(response));
: CompletableFuture.completedFuture(response));
} }
CompletableFuture<ResourceMetadata> httpHead(String url) { CompletableFuture<ResourceMetadata> httpHead(String url) {
@ -280,7 +281,8 @@ public class Downloader {
boolean supportsRangeRequest = headers.allValues(ACCEPT_RANGES).contains("bytes"); boolean supportsRangeRequest = headers.allValues(ACCEPT_RANGES).contains("bytes");
ResourceMetadata metadata = new ResourceMetadata(location, url, contentLength, supportsRangeRequest); ResourceMetadata metadata = new ResourceMetadata(location, url, contentLength, supportsRangeRequest);
return HttpResponse.BodyHandlers.replacing(metadata).apply(responseInfo); return HttpResponse.BodyHandlers.replacing(metadata).apply(responseInfo);
}).thenApply(HttpResponse::body); })
.thenApply(HttpResponse::body);
} }
private CompletableFuture<?> httpDownload(ResourceToDownload resource, Path tmpPath) { private CompletableFuture<?> httpDownload(ResourceToDownload resource, Path tmpPath) {
@ -320,9 +322,8 @@ public class Downloader {
try (var fileChannel = FileChannel.open(tmpPath, WRITE)) { try (var fileChannel = FileChannel.open(tmpPath, WRITE)) {
while (range.size() > 0) { while (range.size() > 0) {
try ( try (
var inputStream = (ranges || range.start > 0) var inputStream = (ranges || range.start > 0) ? openStreamRange(canonicalUrl, range.start, range.end) :
? openStreamRange(canonicalUrl, range.start, range.end) openStream(canonicalUrl);
: openStream(canonicalUrl);
var input = new ProgressChannel(Channels.newChannel(inputStream), resource.progress) var input = new ProgressChannel(Channels.newChannel(inputStream), resource.progress)
) { ) {
// ensure this file has been allocated up to the start of this block // ensure this file has been allocated up to the start of this block
@ -333,8 +334,8 @@ public class Downloader {
throw new IOException("Transferred 0 bytes but " + range.size() + " expected: " + canonicalUrl); throw new IOException("Transferred 0 bytes but " + range.size() + " expected: " + canonicalUrl);
} else if (transferred != range.size() && !metadata.acceptRange) { } else if (transferred != range.size() && !metadata.acceptRange) {
throw new IOException( throw new IOException(
"Transferred " + transferred + " bytes but " + range.size() + " expected: " + canonicalUrl "Transferred " + transferred + " bytes but " + range.size() + " expected: " + canonicalUrl +
+ " and server does not support range requests"); " and server does not support range requests");
} }
range = new Range(range.start + transferred, range.end); range = new Range(range.start + transferred, range.end);
} }

Wyświetl plik

@ -19,8 +19,7 @@ public class FileUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(FileUtils.class); private static final Logger LOGGER = LoggerFactory.getLogger(FileUtils.class);
private FileUtils() { private FileUtils() {}
}
/** Returns a stream that lists all files in {@code fileSystem}. */ /** Returns a stream that lists all files in {@code fileSystem}. */
public static Stream<Path> walkFileSystem(FileSystem fileSystem) { public static Stream<Path> walkFileSystem(FileSystem fileSystem) {

Wyświetl plik

@ -31,7 +31,7 @@ public class Geofabrik {
* Fetches the Geofabrik index and searches for a {@code .osm.pbf} resource to download where ID or name field * Fetches the Geofabrik index and searches for a {@code .osm.pbf} resource to download where ID or name field
* contains all the tokens in {@code searchQuery}. * contains all the tokens in {@code searchQuery}.
* <p> * <p>
* If an exact match is found, returns that. Otherwise, looks for a resource that contains {@code searchQuery} as a * If an exact match is found, returns that. Otherwise, looks for a resource that contains {@code searchQuery} as a
* substring. * substring.
* <p> * <p>
* The index is only fetched once and cached after that. * The index is only fetched once and cached after that.
@ -48,8 +48,10 @@ public class Geofabrik {
private synchronized static IndexJson getAndCacheIndex(PlanetilerConfig config) { private synchronized static IndexJson getAndCacheIndex(PlanetilerConfig config) {
if (index == null) { if (index == null) {
try (InputStream inputStream = Downloader.openStream("https://download.geofabrik.de/index-v1-nogeom.json", try (
config)) { InputStream inputStream = Downloader.openStream("https://download.geofabrik.de/index-v1-nogeom.json",
config)
) {
index = parseIndexJson(inputStream); index = parseIndexJson(inputStream);
} catch (IOException e) { } catch (IOException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);

Wyświetl plik

@ -19,12 +19,12 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
* Parse utilities ported to Java from <a href="https://github.com/omniscale/imposm3/blob/master/mapping/columns.go">omniscale/imposm3:mapping/columns.go</a> * Parse utilities ported to Java from <a href=
* "https://github.com/omniscale/imposm3/blob/master/mapping/columns.go">omniscale/imposm3:mapping/columns.go</a>
*/ */
public class Imposm3Parsers { public class Imposm3Parsers {
private Imposm3Parsers() { private Imposm3Parsers() {}
}
private static String string(Object object) { private static String string(Object object) {
return object == null ? null : object.toString(); return object == null ? null : object.toString();

Wyświetl plik

@ -8,8 +8,7 @@ import org.slf4j.MDC;
*/ */
public class LogUtil { public class LogUtil {
private LogUtil() { private LogUtil() {}
}
private static final String STAGE_KEY = "stage"; private static final String STAGE_KEY = "stage";

Wyświetl plik

@ -8,8 +8,7 @@ import java.util.regex.Pattern;
*/ */
public class Parse { public class Parse {
private Parse() { private Parse() {}
}
private static final Pattern INT_SUBSTRING_PATTERN = Pattern.compile("^(-?\\d+)(\\D|$)"); private static final Pattern INT_SUBSTRING_PATTERN = Pattern.compile("^(-?\\d+)(\\D|$)");
private static final Pattern TO_ROUND_INT_SUBSTRING_PATTERN = Pattern.compile("^(-?[\\d.]+)(\\D|$)"); private static final Pattern TO_ROUND_INT_SUBSTRING_PATTERN = Pattern.compile("^(-?[\\d.]+)(\\D|$)");

Wyświetl plik

@ -8,20 +8,24 @@ import com.onthegomap.planetiler.collection.FeatureGroup;
* ordering approximates the desired ordering. * ordering approximates the desired ordering.
* <p> * <p>
* Sort keys get packed into {@link FeatureGroup#SORT_KEY_BITS} bits, so sort key components need to specify the range * Sort keys get packed into {@link FeatureGroup#SORT_KEY_BITS} bits, so sort key components need to specify the range
* and number of levels the range gets packed into. Requests that exceed the total number of available levels will * and number of levels the range gets packed into. Requests that exceed the total number of available levels will fail.
* fail.
* <p> * <p>
* To sort by a field descending, specify its range from high to low. * To sort by a field descending, specify its range from high to low.
* <p> * <p>
* For example this SQL ordering: * For example this SQL ordering:
* <pre>{@code *
* <pre>
* {@code
* ORDER BY rank ASC, * ORDER BY rank ASC,
* population DESC, * population DESC,
* length(name) ASC * length(name) ASC
* }</pre> * }
* </pre>
* <p> * <p>
* would become: * would become:
* <pre>{@code *
* <pre>
* {@code
* feature.setSortKey( * feature.setSortKey(
* SortKey * SortKey
* .orderByInt(rank, MIN_RANK, MAX_RANK) * .orderByInt(rank, MIN_RANK, MAX_RANK)
@ -29,7 +33,8 @@ import com.onthegomap.planetiler.collection.FeatureGroup;
* .thenByInt(name.length(), 0, MAX_LENGTH) * .thenByInt(name.length(), 0, MAX_LENGTH)
* .get() * .get()
* ) * )
* }</pre> * }
* </pre>
*/ */
public class SortKey { public class SortKey {
@ -37,8 +42,7 @@ public class SortKey {
private long possibleValues = 1; private long possibleValues = 1;
private int result = 0; private int result = 0;
private SortKey() { private SortKey() {}
}
/** Returns a new sort key where elements with {@code value == true} sort after ones where {@code value == false} */ /** Returns a new sort key where elements with {@code value == true} sort after ones where {@code value == false} */
public static SortKey orderByTruesLast(boolean value) { public static SortKey orderByTruesLast(boolean value) {

Wyświetl plik

@ -51,8 +51,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* A utility to download name translations from wikidata for all OSM elements with a <a * A utility to download name translations from wikidata for all OSM elements with a
* href="https://wiki.openstreetmap.org/wiki/Key:wikidata">wikidata tag</a>. * <a href="https://wiki.openstreetmap.org/wiki/Key:wikidata">wikidata tag</a>.
*/ */
public class Wikidata { public class Wikidata {
@ -371,8 +371,7 @@ public class Wikidata {
private final LongObjectMap<Map<String, String>> data = Hppc.newLongObjectHashMap(); private final LongObjectMap<Map<String, String>> data = Hppc.newLongObjectHashMap();
public WikidataTranslations() { public WikidataTranslations() {}
}
/** Returns a map from language code to translated name for {@code qid}. */ /** Returns a map from language code to translated name for {@code qid}. */
public Map<String, String> get(long qid) { public Map<String, String> get(long qid) {

Wyświetl plik

@ -64,15 +64,14 @@ public interface ZoomFunction<T> extends IntFunction<T> {
} }
/** /**
* A zoom function that lets you set the value to return for a zoom level in meters and when called, it returns how * A zoom function that lets you set the value to return for a zoom level in meters and when called, it returns how
* many pixels long that number of meters is at the equator. * many pixels long that number of meters is at the equator.
*/ */
class MeterToPixelThresholds implements ZoomFunction<Number> { class MeterToPixelThresholds implements ZoomFunction<Number> {
private final TreeMap<Integer, Number> levels = new TreeMap<>(); private final TreeMap<Integer, Number> levels = new TreeMap<>();
private MeterToPixelThresholds() { private MeterToPixelThresholds() {}
}
/** Sets the value to return at {@code zoom} in meters. */ /** Sets the value to return at {@code zoom} in meters. */
public MeterToPixelThresholds put(int zoom, double meters) { public MeterToPixelThresholds put(int zoom, double meters) {

Wyświetl plik

@ -13,20 +13,24 @@ import javax.annotation.concurrent.ThreadSafe;
* When a group of worker threads are processing large blocks, some may finish early, resulting in idle time at the end * When a group of worker threads are processing large blocks, some may finish early, resulting in idle time at the end
* waiting for the "long pole in the tent" to finish: * waiting for the "long pole in the tent" to finish:
* *
* <pre>{@code * <pre>
* {@code
* busy idle | done * busy idle | done
* worker1: ===========>xxxxxx| * worker1: ===========>xxxxxx|
* worker2: ===============>xx| * worker2: ===============>xx|
* worker3: =================>| * worker3: =================>|
* worker4: =============>xxxx| * worker4: =============>xxxx|
* }</pre> * }
* </pre>
* <p> * <p>
* This utility wraps the operation to perform on each element and then works through items in 3 phases: * This utility wraps the operation to perform on each element and then works through items in 3 phases:
* *
* <ol> * <ol>
* <li>If all threads are still busy, process it in the same thread</li> * <li>If all threads are still busy, process it in the same thread</li>
* <li>If some threads are done, enqueue the item onto a work queue (but if it is full, just process it in the same thread)</li> * <li>If some threads are done, enqueue the item onto a work queue (but if it is full, just process it in the same
* <li>When the thread is done processing input elements, then process items off of the work queue until it is empty and all other workers are finished</li> * thread)</li>
* <li>When the thread is done processing input elements, then process items off of the work queue until it is empty and
* all other workers are finished</li>
* </ol> * </ol>
* *
* @param <T> The type of element being processed * @param <T> The type of element being processed

Wyświetl plik

@ -104,4 +104,3 @@ public class WeightedHandoffQueue<T> implements AutoCloseable, IterableOnce<T> {
return itemBatch == null ? null : itemBatch.poll(); return itemBatch == null ? null : itemBatch.poll();
} }
} }

Wyświetl plik

@ -19,9 +19,9 @@ import java.util.function.Consumer;
* <p> * <p>
* Wraps a standard {@link BlockingDeque}, with a few customizations: * Wraps a standard {@link BlockingDeque}, with a few customizations:
* <ul> * <ul>
* <li>items are buffered into configurable-sized batches before putting on the actual queue to reduce contention</li> * <li>items are buffered into configurable-sized batches before putting on the actual queue to reduce contention</li>
* <li>writers can mark the queue "finished" with {@link #close()} and readers will get {@code null} when there are * <li>writers can mark the queue "finished" with {@link #close()} and readers will get {@code null} when there are no
* no more items to read</li> * more items to read</li>
* </ul> * </ul>
* <p> * <p>
* Once a thread starts reading from this queue, it needs to finish otherwise all items might not be read. * Once a thread starts reading from this queue, it needs to finish otherwise all items might not be read.
@ -123,7 +123,9 @@ public class WorkQueue<T> implements AutoCloseable, IterableOnce<T>, Consumer<T>
return (pendingBatchesCapacity + writers.size() + readers.size()) * batchSize; return (pendingBatchesCapacity + writers.size() + readers.size()) * batchSize;
} }
/** Caches thread-local values so that a single thread can accept new items without having to do thread-local lookups. */ /**
* Caches thread-local values so that a single thread can accept new items without having to do thread-local lookups.
*/
private class WriterForThread implements Consumer<T> { private class WriterForThread implements Consumer<T> {
final AtomicReference<Queue<T>> writeBatchRef = new AtomicReference<>(null); final AtomicReference<Queue<T>> writeBatchRef = new AtomicReference<>(null);
@ -173,7 +175,9 @@ public class WorkQueue<T> implements AutoCloseable, IterableOnce<T>, Consumer<T>
} }
} }
/** Caches thread-local values so that a single thread can read new items without having to do thread-local lookups. */ /**
* Caches thread-local values so that a single thread can read new items without having to do thread-local lookups.
*/
private class ReaderForThread implements IterableOnce<T> { private class ReaderForThread implements IterableOnce<T> {
Queue<T> readBatch = null; Queue<T> readBatch = null;
@ -221,4 +225,3 @@ public class WorkQueue<T> implements AutoCloseable, IterableOnce<T>, Consumer<T>
} }
} }
} }

Wyświetl plik

@ -16,7 +16,9 @@ import java.util.function.Consumer;
* A mini-framework for chaining sequential steps that run in dedicated threads with a queue between each. * A mini-framework for chaining sequential steps that run in dedicated threads with a queue between each.
* <p> * <p>
* For example: * For example:
* <pre>{@code *
* <pre>
* {@code
* WorkerPipeline.start("name", stats) * WorkerPipeline.start("name", stats)
* .readFrom("reader", List.of(1, 2, 3)) * .readFrom("reader", List.of(1, 2, 3))
* .addBuffer("reader_queue", 10) * .addBuffer("reader_queue", 10)
@ -24,13 +26,14 @@ import java.util.function.Consumer;
* .addBuffer("writer_queue", 10) * .addBuffer("writer_queue", 10)
* .sinkToConsumer("writer", 1, result -> writeToDisk(result)) * .sinkToConsumer("writer", 1, result -> writeToDisk(result))
* .await(); * .await();
* }</pre> * }
* </pre>
* <p> * <p>
* NOTE: to do any forking/joining, you must construct and wire-up queues and each sequence of steps manually. * NOTE: to do any forking/joining, you must construct and wire-up queues and each sequence of steps manually.
* *
* @param <T> input type of this pipeline * @param <T> input type of this pipeline
*/ */
public record WorkerPipeline<T>( public record WorkerPipeline<T> (
String name, String name,
WorkerPipeline<?> previous, WorkerPipeline<?> previous,
WorkQueue<T> inputQueue, WorkQueue<T> inputQueue,
@ -213,7 +216,7 @@ public record WorkerPipeline<T>(
* *
* @param <O> type of elements that the next step must process * @param <O> type of elements that the next step must process
*/ */
public record Builder<O>( public record Builder<O> (
String prefix, String prefix,
String name, String name,
// keep track of previous elements so that build can wire-up the computation graph // keep track of previous elements so that build can wire-up the computation graph

Wyświetl plik

@ -90,8 +90,7 @@ public class PlanetilerTests {
} }
@Override @Override
public void close() { public void close() {}
}
}.process(featureGroup, config); }.process(featureGroup, config);
} }
@ -1507,8 +1506,7 @@ public class PlanetilerTests {
} }
@Override @Override
public void release() { public void release() {}
}
@Override @Override
public List<VectorTile.Feature> postProcessLayerFeatures(String layer, int zoom, public List<VectorTile.Feature> postProcessLayerFeatures(String layer, int zoom,
@ -1577,9 +1575,9 @@ public class PlanetilerTests {
Path tempOsm = tempDir.resolve("monaco-temp.osm.pbf"); Path tempOsm = tempDir.resolve("monaco-temp.osm.pbf");
Files.copy(originalOsm, tempOsm); Files.copy(originalOsm, tempOsm);
Planetiler.create(Arguments.fromArgs( Planetiler.create(Arguments.fromArgs(
"--tmpdir", tempDir.toString(), "--tmpdir", tempDir.toString(),
"--free-osm-after-read" "--free-osm-after-read"
)) ))
.setProfile(new Profile.NullProfile() { .setProfile(new Profile.NullProfile() {
@Override @Override
public void processFeature(SourceFeature source, FeatureCollector features) { public void processFeature(SourceFeature source, FeatureCollector features) {
@ -1625,25 +1623,25 @@ public class PlanetilerTests {
@Test @Test
public void testPlanetilerMemoryCheck(@TempDir Path tempDir) { public void testPlanetilerMemoryCheck(@TempDir Path tempDir) {
assertThrows(Exception.class, () -> runWithProfile(tempDir, new Profile.NullProfile() { assertThrows(Exception.class, () -> runWithProfile(tempDir, new Profile.NullProfile() {
@Override @Override
public long estimateIntermediateDiskBytes(long osmSize) { public long estimateIntermediateDiskBytes(long osmSize) {
return Long.MAX_VALUE / 10L; return Long.MAX_VALUE / 10L;
} }
}, false) }, false)
); );
assertThrows(Exception.class, () -> runWithProfile(tempDir, new Profile.NullProfile() { assertThrows(Exception.class, () -> runWithProfile(tempDir, new Profile.NullProfile() {
@Override @Override
public long estimateOutputBytes(long osmSize) { public long estimateOutputBytes(long osmSize) {
return Long.MAX_VALUE / 10L; return Long.MAX_VALUE / 10L;
} }
}, false) }, false)
); );
assertThrows(Exception.class, () -> runWithProfile(tempDir, new Profile.NullProfile() { assertThrows(Exception.class, () -> runWithProfile(tempDir, new Profile.NullProfile() {
@Override @Override
public long estimateRamRequired(long osmSize) { public long estimateRamRequired(long osmSize) {
return Long.MAX_VALUE / 10L; return Long.MAX_VALUE / 10L;
} }
}, false) }, false)
); );
} }

Wyświetl plik

@ -504,11 +504,9 @@ public class TestUtils {
public record Way( public record Way(
long id, long id,
@JacksonXmlProperty(localName = "nd") @JacksonXmlProperty(localName = "nd")
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlElementWrapper(useWrapping = false) List<NodeRef> nodeRefs,
List<NodeRef> nodeRefs,
@JacksonXmlProperty(localName = "tag") @JacksonXmlProperty(localName = "tag")
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlElementWrapper(useWrapping = false) List<Tag> tags
List<Tag> tags
) {} ) {}
@JacksonXmlRootElement(localName = "member") @JacksonXmlRootElement(localName = "member")
@ -520,11 +518,9 @@ public class TestUtils {
public record Relation( public record Relation(
long id, long id,
@JacksonXmlProperty(localName = "member") @JacksonXmlProperty(localName = "member")
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlElementWrapper(useWrapping = false) List<RelationMember> members,
List<RelationMember> members,
@JacksonXmlProperty(localName = "tag") @JacksonXmlProperty(localName = "tag")
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlElementWrapper(useWrapping = false) List<Tag> tags
List<Tag> tags
) {} ) {}
// @JsonIgnoreProperties(ignoreUnknown = true) // @JsonIgnoreProperties(ignoreUnknown = true)
@ -535,14 +531,11 @@ public class TestUtils {
String attribution, String attribution,
String license, String license,
@JacksonXmlProperty(localName = "node") @JacksonXmlProperty(localName = "node")
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlElementWrapper(useWrapping = false) List<Node> nodes,
List<Node> nodes,
@JacksonXmlProperty(localName = "way") @JacksonXmlProperty(localName = "way")
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlElementWrapper(useWrapping = false) List<Way> ways,
List<Way> ways,
@JacksonXmlProperty(localName = "relation") @JacksonXmlProperty(localName = "relation")
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlElementWrapper(useWrapping = false) List<Relation> relation
List<Relation> relation
) {} ) {}
private static final XmlMapper xmlMapper = new XmlMapper(); private static final XmlMapper xmlMapper = new XmlMapper();
@ -594,8 +587,7 @@ public class TestUtils {
int minzoom, int maxzoom) { int minzoom, int maxzoom) {
try { try {
List<String> failures = new ArrayList<>(); List<String> failures = new ArrayList<>();
outer: outer: for (int zoom = 0; zoom <= 14; zoom++) {
for (int zoom = 0; zoom <= 14; zoom++) {
boolean shouldFind = zoom >= minzoom && zoom <= maxzoom; boolean shouldFind = zoom >= minzoom && zoom <= maxzoom;
var coord = TileCoord.aroundLngLat(lng, lat, zoom); var coord = TileCoord.aroundLngLat(lng, lat, zoom);
Geometry tilePoint = GeoUtils.point(coord.lngLatToTileCoords(lng, lat)); Geometry tilePoint = GeoUtils.point(coord.lngLatToTileCoords(lng, lat));

Wyświetl plik

@ -48,7 +48,8 @@ import org.locationtech.jts.precision.GeometryPrecisionReducer;
import vector_tile.VectorTileProto; import vector_tile.VectorTileProto;
/** /**
* This class is copied from https://github.com/ElectronicChartCentre/java-vector-tile/blob/master/src/test/java/no/ecc/vectortile/VectorTileEncoderTest.java * This class is copied from
* https://github.com/ElectronicChartCentre/java-vector-tile/blob/master/src/test/java/no/ecc/vectortile/VectorTileEncoderTest.java
* and modified based on the changes in VectorTileEncoder, and adapted to junit 5. * and modified based on the changes in VectorTileEncoder, and adapted to junit 5.
*/ */
public class VectorTileTest { public class VectorTileTest {
@ -366,59 +367,58 @@ public class VectorTileTest {
var scaleUp = AffineTransformation.scaleInstance(256d / 4096, 256d / 4096); var scaleUp = AffineTransformation.scaleInstance(256d / 4096, 256d / 4096);
var scaleDown = scaleUp.getInverse(); var scaleDown = scaleUp.getInverse();
return Stream.of( return Stream.of(
newPoint(0, 0), newPoint(0, 0),
newPoint(0.25, -0.25), newPoint(0.25, -0.25),
newPoint(1.25, 1.25),
newPoint(1.5, 1.5),
newMultiPoint(
newPoint(1.25, 1.25), newPoint(1.25, 1.25),
newPoint(1.5, 1.5), newPoint(1.5, 1.5)
newMultiPoint( ),
newPoint(1.25, 1.25), newLineString(0, 0, 1.2, 1.2),
newPoint(1.5, 1.5) newLineString(0, 0, 0.1, 0.1),
), newLineString(0, 0, 1, 1, 1.2, 1.2, 2, 2),
newLineString(0, 0, 1.2, 1.2), newLineString(8000, 8000, 8000, 8001, 8001, 8001),
newLineString(-4000, -4000, -4000, -4001, -4001, -4001),
newMultiLineString(
newLineString(0, 0, 1, 1),
newLineString(1.1, 1.1, 2, 2)
),
newMultiLineString(
newLineString(0, 0, 0.1, 0.1), newLineString(0, 0, 0.1, 0.1),
newLineString(0, 0, 1, 1, 1.2, 1.2, 2, 2), newLineString(1.1, 1.1, 2, 2)
newLineString(8000, 8000, 8000, 8001, 8001, 8001), ),
newLineString(-4000, -4000, -4000, -4001, -4001, -4001), newMultiLineString(
newMultiLineString( newLineString(-10, -10, -9, -9),
newLineString(0, 0, 1, 1), newLineString(0, 0, 0.1, 0.1),
newLineString(1.1, 1.1, 2, 2) newLineString(1.1, 1.1, 2, 2)
), ),
newMultiLineString( newPolygon(0, 0, 1, 0, 1, 1, 0, 1, 0, 0),
newLineString(0, 0, 0.1, 0.1), newPolygon(0, 0, 0.1, 0, 0.1, 0.1, 0, 0.1, 0, 0),
newLineString(1.1, 1.1, 2, 2) newPolygon(0, 0, 1, 0, 1, 0.1, 1, 1, 0, 1, 0, 0),
), newMultiPolygon(
newMultiLineString(
newLineString(-10, -10, -9, -9),
newLineString(0, 0, 0.1, 0.1),
newLineString(1.1, 1.1, 2, 2)
),
newPolygon(0, 0, 1, 0, 1, 1, 0, 1, 0, 0), newPolygon(0, 0, 1, 0, 1, 1, 0, 1, 0, 0),
newPolygon(0, 0, 0.1, 0, 0.1, 0.1, 0, 0.1, 0, 0), newPolygon(0, 0, -1, 0, -1, -1, 0, -1, 0, 0)
newPolygon(0, 0, 1, 0, 1, 0.1, 1, 1, 0, 1, 0, 0), ),
newMultiPolygon( newPolygon(0, 0, 1, 0, 1, 1, 0, 1, 0, 0.1, 0, 0)
newPolygon(0, 0, 1, 0, 1, 1, 0, 1, 0, 0), ).map(scaleUp::transform)
newPolygon(0, 0, -1, 0, -1, -1, 0, -1, 0, 0) .flatMap(geometry -> scales.stream().flatMap(scale -> Stream.of(
), dynamicTest(scaleDown.transform(geometry) + " scale: " + scale, () -> {
newPolygon(0, 0, 1, 0, 1, 1, 0, 1, 0, 0.1, 0, 0) PrecisionModel pm = new PrecisionModel((4096 << scale) / 256d);
).map(scaleUp::transform) assertSameGeometry(
.flatMap(geometry -> scales.stream().flatMap(scale -> GeometryPrecisionReducer.reduce(geometry, pm),
Stream.of( VectorTile.encodeGeometry(geometry, scale).decode()
dynamicTest(scaleDown.transform(geometry) + " scale: " + scale, () -> { );
PrecisionModel pm = new PrecisionModel((4096 << scale) / 256d); }),
assertSameGeometry( dynamicTest(scaleDown.transform(geometry) + " unscale: " + scale, () -> {
GeometryPrecisionReducer.reduce(geometry, pm), PrecisionModel pm = new PrecisionModel((4096 << scale) / 256d);
VectorTile.encodeGeometry(geometry, scale).decode() PrecisionModel pm0 = new PrecisionModel(4096d / 256);
); assertSameGeometry(
}), GeometryPrecisionReducer.reduce(GeometryPrecisionReducer.reduce(geometry, pm), pm0),
dynamicTest(scaleDown.transform(geometry) + " unscale: " + scale, () -> { VectorTile.encodeGeometry(geometry, scale).unscale().decode()
PrecisionModel pm = new PrecisionModel((4096 << scale) / 256d); );
PrecisionModel pm0 = new PrecisionModel(4096d / 256); })
assertSameGeometry( )
GeometryPrecisionReducer.reduce(GeometryPrecisionReducer.reduce(geometry, pm), pm0),
VectorTile.encodeGeometry(geometry, scale).unscale().decode()
);
})
)
)); ));
} }

Wyświetl plik

@ -279,9 +279,8 @@ public class FeatureGroupTest {
int tileB, byte layerB, int sortKeyB, boolean hasGroupB int tileB, byte layerB, int sortKeyB, boolean hasGroupB
) { ) {
assertTrue( assertTrue(
FeatureGroup.encodeKey(tileA, layerA, sortKeyA, hasGroupA) FeatureGroup.encodeKey(tileA, layerA, sortKeyA, hasGroupA) < FeatureGroup.encodeKey(tileB, layerB, sortKeyB,
< hasGroupB)
FeatureGroup.encodeKey(tileB, layerB, sortKeyB, hasGroupB)
); );
} }

Wyświetl plik

@ -62,15 +62,15 @@ public class OsmInputFileTest {
@Test @Test
public void testGetHeader() { public void testGetHeader() {
assertEquals(new OsmHeader( assertEquals(new OsmHeader(
expectedBounds, expectedBounds,
List.of("OsmSchema-V0.6", "DenseNodes"), List.of("OsmSchema-V0.6", "DenseNodes"),
List.of(), List.of(),
"osmium/1.8.0", "osmium/1.8.0",
"", "",
Instant.parse("2021-04-21T20:21:46Z"), Instant.parse("2021-04-21T20:21:46Z"),
2947, 2947,
"http://download.geofabrik.de/europe/monaco-updates" "http://download.geofabrik.de/europe/monaco-updates"
), ),
new OsmInputFile(path).getHeader() new OsmInputFile(path).getHeader()
); );
} }

Some files were not shown because too many files have changed in this diff Show More