Skip to content

Commit b51f189

Browse files
authored
Merge pull request #25 from Ercalvez/kmp
Port to Kotlin Multiplatform
2 parents 94d47f7 + 7e66378 commit b51f189

File tree

104 files changed

+3009
-4179
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+3009
-4179
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
# 6.0
4+
5+
The library is now a Kotlin Multiplatform library. This is a breaking API change. There is also no separate artifact for Android anymore.
6+
37
# 5.2
48

59
- Add support placeholders for preset names (breaking change in [v5.0.0](https://github.com/ideditor/schema-builder/blob/main/CHANGELOG.md#510) of iD presets schema)

README.md

+66-70
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,101 @@
11
# osmfeatures
22

3-
A dictionary of OSM map features, accessible by terms and by tags, for Java and Android.
3+
A Kotlin multiplatform dictionary of OSM map features, accessible by terms and by tags. Supported platforms are Android, JVM and iOS.
44

5-
Requires Java 8.
5+
Due to heavy use of indices, it is very fast.
66

7-
## Copyright and License
8-
9-
© 2019-2022 Tobias Zwick. This library is released under the terms of the [Apache License Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt).
7+
It is currently used in [StreetComplete](https://github.com/streetcomplete/streetcomplete).
108

11-
## Installation
12-
13-
Add [`de.westnordost:osmfeatures:5.2`](https://mvnrepository.com/artifact/de.westnordost/osmfeatures/5.2) as a Maven dependency or download the jar from there.
9+
## Copyright and License
1410

15-
For Android, use [`de.westnordost:osmfeatures-android:5.2`](https://mvnrepository.com/artifact/de.westnordost/osmfeatures-android/5.2).
11+
© 2019-2024 Tobias Zwick. This library is released under the terms of the Apache License Version 2.0.
1612

1713
## Usage
1814

15+
Add [de.westnordost:osmfeatures:6.0](https://mvnrepository.com/artifact/de.westnordost/osmfeatures/6.0) as a Maven dependency or download the jar from there.
16+
1917
### Get the data
2018

2119
The data for the dictionary is not maintained in this repository.
22-
It actually uses the [preset data from iD](https://github.com/openstreetmap/id-tagging-schema/blob/main/dist/presets.json) and [the translations of the presets](https://github.com/openstreetmap/id-tagging-schema/tree/main/dist/translations).
23-
Just dump all the translations and the presets.json into the same directory.
24-
Do not forget to give attribution to iD since you are using their data.
25-
26-
If you use gradle as your build tool, the easiest way to get this data is to put this task into your `build.gradle` and either execute this task manually from time to time or make the build process depend on it (by adding `preBuild.dependsOn(downloadPresets)`):
27-
28-
```groovy
29-
import groovy.json.JsonSlurper
30-
31-
task downloadPresets {
32-
doLast {
33-
def targetDir = "$projectDir/path/to/where/the/data/should/go"
34-
def presetsUrl = new URL("https://raw.githubusercontent.com/openstreetmap/id-tagging-schema/main/dist/presets.json")
35-
def contentsUrl = new URL("https://api.github.com/repos/openstreetmap/id-tagging-schema/contents/dist/translations")
36-
37-
new File("$targetDir/presets.json").withOutputStream { it << presetsUrl.openStream() }
38-
39-
def slurper = new JsonSlurper()
40-
slurper.parse(contentsUrl, "UTF-8").each {
41-
if(it.type == "file") {
42-
def filename = it.name.substring(0, it.name.indexOf("."))
43-
def javaLanguageTag = Locale.forLanguageTag(filename.replace('@','-')).toLanguageTag()
44-
def translationsUrl = new URL(it.download_url)
45-
new File("$targetDir/${javaLanguageTag}.json").withOutputStream { it << translationsUrl.openStream() }
46-
}
47-
}
48-
}
49-
}
50-
```
20+
It actually uses the [preset data from iD](https://github.com/openstreetmap/id-tagging-schema/blob/main/dist/presets.json), [its translations](https://github.com/openstreetmap/id-tagging-schema/tree/main/dist/translations)
21+
and optionally additionally the brand preset data from the [name suggestion index](https://github.com/osmlab/name-suggestion-index).
22+
Each are &copy; iD contributors, licensed under the ISC license.
23+
5124

52-
In StreetComplete (app that uses this library), there is [UpdatePresetsTask.kt](https://github.com/streetcomplete/StreetComplete/blob/master/buildSrc/src/main/java/UpdatePresetsTask.kt) to do this. It's longer but it is maintained and takes care of some more edge cases. Also, take note of [UpdateNsiPresetsTask.kt](https://github.com/streetcomplete/StreetComplete/blob/master/buildSrc/src/main/java/UpdateNsiPresetsTask.kt) which fetches the [name suggestion index presets](https://github.com/osmlab/name-suggestion-index) (=brands).
25+
So, just dump all the translations and the presets.json into the same directory. To be always
26+
up-to-date, it is advisable to have an automatic build task that fetches the current version of the
27+
presets from the repository.
28+
29+
The app for which this library was developed (StreetComplete), uses the following tasks:
30+
- [UpdatePresetsTask.kt](https://github.com/streetcomplete/StreetComplete/blob/master/buildSrc/src/main/java/UpdatePresetsTask.kt) to download presets and selected translations
31+
- [UpdateNsiPresetsTask.kt](https://github.com/streetcomplete/StreetComplete/blob/master/buildSrc/src/main/java/UpdateNsiPresetsTask.kt) to download the brand presets from the [name suggestion index](https://github.com/osmlab/name-suggestion-index)
5332

5433
### Initialize dictionary
5534

56-
Point the dictionary to the directory where the data is located (see above). Use `FeatureDictionary` as a singleton.
57-
```java
58-
FeatureDictionary dictionary = FeatureDictionary.create("path/to/data"));
35+
Point the dictionary to the directory where the data is located (see above). Use `FeatureDictionary` as a singleton, as initialization takes a moment (loading files, building indices).
36+
```kotlin
37+
val dictionary = FeatureDictionary.create(fileSystem, "path/to/data")
5938
```
6039

6140
For Android, use
62-
```java
63-
FeatureDictionary dictionary = AndroidFeatureDictionary.create(assetManager, "path/within/assets/folder/to/data"));
41+
```kotlin
42+
val dictionary = FeatureDictionary.create(assetManager, "path/within/assets/folder/to/data")
6443
```
6544

66-
If brand features from the [name suggestion index](https://github.com/osmlab/name-suggestion-index) (see last paragraph in the previous "Get the data" section) should be included in the dictionary, you can specify the path to these presets as a further parameter. These will be loaded on-demand depending on for which countries you search for.
45+
If brand features from the [name suggestion index](https://github.com/osmlab/name-suggestion-index) should be included in the dictionary, you can specify the path to these presets as a third parameter. These will be loaded on-demand depending on for which countries you search for.
46+
47+
Translations will also be loaded on demand when first querying features using a certain language.
6748

6849
### Find matches by tags
69-
```java
70-
List<Feature> matches = dictionary
71-
.byTags(Map.of("amenity", "bench")) // look for features that have the given tags
72-
.forGeometry(GeometryType.POINT) // limit the search to features that may be points
73-
.forLocale(Locale.GERMAN) // show results in German only, don't fall back to English or unlocalized results
74-
.find();
7550

76-
// prints "Parkbank" (or something like this) or index out of bounds exception
77-
// if no preset for amenity=bench exists that is localized to German
78-
println(matches.get(0).getName());
51+
```kotlin
52+
val matches = dictionary.getByTags(
53+
tags = mapOf("amenity" to "bench"), // look for features that have the given tags
54+
languages = listOf("de"), // show results in German only, don't fall back to English or unlocalized results
55+
geometry = GeometryType.POINT, // limit the search to features that may be points
56+
)
57+
58+
59+
// prints "Parkbank" (or something like this)
60+
// or null if no preset for amenity=bench exists that is localized to German
61+
println(matches[0]?.getName())
7962
```
8063

8164
### Find matches by search word
8265

83-
```java
84-
List<Feature> matches = dictionary
85-
.byTerm("Bank") // look for features matching "Bank"
86-
.forGeometry(GeometryType.AREA) // limit the search to features that may be areas
87-
.forLocale(Locale.GERMAN, null) // show results in German or fall back to unlocalized results
66+
```kotlin
67+
val matches = dictionary.getByTerm(
68+
term = "Bank", // look for features matching "Bank"
69+
languages = listOf("de", null), // show results in German or fall back to unlocalized results
8870
// (brand features are usually not localized)
89-
.inCountry("DE") // also include things (brands) that only exist in Germany
90-
.limit(10) // return at most 10 entries
91-
.find();
92-
// result list will have matches with at least amenity=bank, but not amenity=bench because it is a point-feature
71+
country = "DE", // also include things (brands) that only exist in Germany
72+
geometry = GeometryType.AREA, // limit the search to features that may be areas
73+
)
74+
// result sequence will have matches with at least amenity=bank, but not amenity=bench because it is a point-feature
75+
// if the dictionary contains also brand presets, e.g. "Deutsche Bank" will certainly also be amongst the results
9376
```
9477

9578
### Find by id
9679

80+
```kotlin
81+
val match = dictionary.getById(
82+
id = "amenity/bank",
83+
languages = listOf("de", "en-US", null), // show results in German, otherwise fall back to American
84+
// English or otherwise unlocalized results
85+
country = "DE", // also include things (brands) that only exist in Germany
86+
)
87+
```
88+
89+
### Builders
90+
91+
For a more convenient interface on Java, the above functions continue to be available as builders,
92+
e.g.
93+
9794
```java
98-
Feature feature = dictionary
99-
.byId("amenity/bank")
100-
.forLocale(Locale.GERMAN, // show results in German, otherwise fall back to English etc.
101-
Locale.ENGLISH,
102-
null)
103-
.inCountry("DE") // also include things (brands) that only exist in Germany
104-
.get();
95+
List<Feature> matches = dictionary
96+
.byTags(Map.of("amenity", "bench"))
97+
.forGeometry(GeometryType.POINT)
98+
.inLanguage("de")
99+
.find();
105100
```
101+

build.gradle

-46
This file was deleted.

build.gradle.kts

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
plugins {
2+
kotlin("multiplatform") version "1.9.24"
3+
id("com.android.library") version "8.2.0"
4+
id("org.jetbrains.dokka") version "1.9.20"
5+
6+
id("maven-publish")
7+
id("signing")
8+
}
9+
10+
kotlin {
11+
group = "de.westnordost"
12+
version = "6.0"
13+
14+
jvm()
15+
androidTarget {
16+
publishLibraryVariants("release")
17+
compilations.all {
18+
kotlinOptions {
19+
jvmTarget = "1.8"
20+
}
21+
}
22+
}
23+
iosSimulatorArm64()
24+
iosX64()
25+
iosArm64()
26+
27+
applyDefaultHierarchyTemplate()
28+
29+
sourceSets {
30+
commonMain {
31+
dependencies {
32+
// multiplatform file access
33+
api("org.jetbrains.kotlinx:kotlinx-io-core:0.3.4")
34+
// parsing the preset.json
35+
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
36+
// for stripping diacritics correctly
37+
implementation("com.doist.x:normalize:1.0.5")
38+
}
39+
}
40+
commonTest {
41+
dependencies {
42+
implementation(kotlin("test"))
43+
// we are pulling some current preset json from the iD preset repo to see if parsing
44+
// does at least not crash and return something
45+
implementation("io.ktor:ktor-client-core:2.3.11")
46+
implementation("io.ktor:ktor-client-cio:2.3.11")
47+
// ktor-client is a suspending API, so we need coroutines too
48+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
49+
}
50+
}
51+
}
52+
}
53+
54+
55+
android {
56+
namespace = "de.westnordost.osmfeatures"
57+
compileSdk = 33
58+
defaultConfig {
59+
minSdk = 21
60+
}
61+
}
62+
63+
val javadocJar = tasks.register<Jar>("javadocJar") {
64+
archiveClassifier.set("javadoc")
65+
from(tasks.dokkaHtml)
66+
}
67+
68+
publishing {
69+
publications {
70+
withType<MavenPublication> {
71+
artifactId = rootProject.name + if (name != "kotlinMultiplatform") "-$name" else ""
72+
artifact(javadocJar)
73+
74+
pom {
75+
name.set("osmfeatures")
76+
description.set("Java library to translate OSM tags to and from localized names.")
77+
url.set("https://github.com/westnordost/osmfeatures")
78+
79+
licenses {
80+
license {
81+
name.set("The Apache License, Version 2.0")
82+
url.set("https://raw.githubusercontent.com/westnordost/osmfeatures/master/LICENSE")
83+
}
84+
}
85+
issueManagement {
86+
system.set("GitHub")
87+
url.set("https://github.com/westnordost/osmfeatures/issues")
88+
}
89+
scm {
90+
connection.set("https://github.com/westnordost/osmfeatures.git")
91+
url.set("https://github.com/westnordost/osmfeatures")
92+
}
93+
developers {
94+
developer {
95+
id.set("westnordost")
96+
name.set("Tobias Zwick")
97+
email.set("osm@westnordost.de")
98+
}
99+
}
100+
}
101+
}
102+
}
103+
repositories {
104+
maven {
105+
name = "oss"
106+
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
107+
credentials {
108+
val ossrhUsername: String by project
109+
val ossrhPassword: String by project
110+
username = ossrhUsername
111+
password = ossrhPassword
112+
}
113+
}
114+
}
115+
}
116+
117+
signing {
118+
sign(publishing.publications)
119+
}
120+
121+
122+
// FIXME - workaround for https://github.com/gradle/gradle/issues/26091
123+
val signingTasks = tasks.withType<Sign>()
124+
tasks.withType<AbstractPublishToMaven>().configureEach {
125+
mustRunAfter(signingTasks)
126+
}

gradle.properties

+4-19
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,7 @@
1-
# Project-wide Gradle settings.
2-
3-
# IDE (e.g. Android Studio) users:
4-
# Gradle settings configured through the IDE *will override*
5-
# any settings specified in this file.
6-
7-
# For more details on how to configure your build environment visit
8-
# http://www.gradle.org/docs/current/userguide/build_environment.html
9-
10-
# Specifies the JVM arguments used for the daemon process.
11-
# The setting is particularly useful for tweaking memory settings.
12-
org.gradle.jvmargs=-Xmx1536m -Dfile.encoding=UTF-8
13-
14-
# When configured, Gradle will run in incubating parallel mode.
15-
# This option should only be used with decoupled projects. More details, visit
16-
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17-
# org.gradle.parallel=true
18-
19-
systemProp.file.encoding=utf-8
1+
# Gradle
2+
org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
3+
org.gradle.caching=true
4+
org.gradle.configuration-cache=true
205

216
signing.keyId=08A11DBC
227
signing.password=
+6-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#Thu Mar 04 22:04:30 CET 2021
2-
distributionBase=GRADLE_USER_HOME
3-
distributionPath=wrapper/dists
4-
zipStoreBase=GRADLE_USER_HOME
5-
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
1+
#Fri Dec 22 21:31:41 CET 2023
2+
distributionBase=GRADLE_USER_HOME
3+
distributionPath=wrapper/dists
4+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
5+
zipStoreBase=GRADLE_USER_HOME
6+
zipStorePath=wrapper/dists

library-android/.gitignore

-1
This file was deleted.

0 commit comments

Comments
 (0)