Home

Awesome

osmfeatures

A Kotlin multiplatform dictionary of OSM map features, accessible by terms and by tags. Supported platforms are Android, JVM and iOS.

Due to heavy use of indices, it is very fast.

It is currently used in StreetComplete.

Copyright and License

© 2019-2024 Tobias Zwick. This library is released under the terms of the Apache License Version 2.0.

Usage

Add de.westnordost:osmfeatures:6.2 as a Maven dependency or download the jar from there.

Get the data

The data for the dictionary is not maintained in this repository. It actually uses the preset data from iD, its translations and optionally additionally the brand preset data from the name suggestion index. Each are © iD contributors, licensed under the ISC license.

So, just dump all the translations and the presets.json into the same directory. To be always up-to-date, it is advisable to have an automatic build task that fetches the current version of the presets from the repository.

The app for which this library was developed (StreetComplete), uses the following tasks:

Initialize dictionary

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).

val dictionary = FeatureDictionary.create(fileSystem, "path/to/data")

For Android, use

val dictionary = FeatureDictionary.create(assetManager, "path/within/assets/folder/to/data")

If brand features from the 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.

Translations will also be loaded on demand when first querying features using a certain language.

Find matches by tags

val matches = dictionary.getByTags(
    tags = mapOf("amenity" to "bench"), // look for features that have the given tags
    languages = listOf("de"),           // show results in German only, don't fall back to English or unlocalized results
    geometry = GeometryType.POINT,      // limit the search to features that may be points
)                     


// prints "Parkbank" (or something like this)
// or null if no preset for amenity=bench exists that is localized to German
println(matches[0]?.getName())

Find matches by search word

val matches = dictionary.getByTerm(
    term = "Bank",                   // look for features matching "Bank"
    languages = listOf("de", null),  // show results in German or fall back to unlocalized results
                                     // (brand features are usually not localized)
    country = "DE",                  // also include things (brands) that only exist in Germany
    geometry = GeometryType.AREA,    // limit the search to features that may be areas
)
// result sequence will have matches with at least amenity=bank, but not amenity=bench because it is a point-feature
// if the dictionary contains also brand presets, e.g. "Deutsche Bank" will certainly also be amongst the results

Find by id

val match = dictionary.getById(
    id = "amenity/bank",
    languages = listOf("de", "en-US", null), // show results in German, otherwise fall back to American 
                                             // English or otherwise unlocalized results
    country = "DE",                          // also include things (brands) that only exist in Germany
)

Builders

For a more convenient interface on Java, the above functions continue to be available as builders, e.g.

List<Feature> matches = dictionary
    .byTags(Map.of("amenity", "bench"))
    .forGeometry(GeometryType.POINT)
    .inLanguage("de")
    .find();