Skip to main content Link Search Menu Expand Document (external link)

Five-Minute Tutorial

This tutorial assumes that you are already familiar with OpenStreetMap and its data model. If not, read our Introduction to OSM or visit the official OSM website.

Create a Feature Library

  • Download and install the GOL command-line utility

  • Download some OSM data (in PBF format). We suggest starting with a subset for a single country (or smaller part). For example, Germany (file size: 3.5 GB) can be downloaded from GeoFabrik or BBBike.

  • Turn the PBF file into a Geographic Object Library:

    gol build germany germany-latest.osm.pbf
    

    On a multi-core workstation with at least 24 GB of RAM, this should take a few minutes; on an 8-GB dual-core laptop, expect 20 minutes or more. The output will look like this:

    Building germany.gol from germany-latest.osm.pbf using default settings...
    Analyzed germany-latest.osm.pbf in 20s 
    Sorted 86,432,126 features in 1m 13s
    Validated 1023 tiles in 36s
    Compiled 1023 tiles in 1m 24s
    Linked 1023 tiles in 8s
    Build completed in 3m 43s  
    

Use Feature Libraries in Java

Add this Maven dependency to your project:

<dependency>
    <groupId>com.geodesk</groupId>
    <artifactId>geodesk</artifactId>
    <version>0.2.0</version>
</dependency>

Import the GeoDesk packages:

import com.geodesk.feature.*;
import com.geodesk.geom.*;

Open the library:

FeatureLibrary germany = new FeatureLibrary("germany.gol");   

Create a query:

Features lighthouses = germany.select("na[man_made=lighthouse][name][height]");   

This returns a collection of Feature objects representing lighthouses that have names and whose height has been recorded (na indicates that we want features that are mapped as nodes or areas — see Geo-Object Query Language).

Iterate through the features:

for(Feature f: lighthouses)
{
    System.out.format("%s is %f meters tall.\n", 
        f.stringValue("name"), f.doubleValue("height"));      
}   

Typically we want only a specific subset of the collection. The most common case is a bounding-box query:

Box bbox = Box.ofWSEN(8.42, 53.75, 9.07, 53.98);
    // longitude/latitude West, South, East, North
for(Feature f: lighthouses.in(bbox)) ...

Other filters include:

  • Filter by type: .nodes(), .ways(), .relations()

  • Spatial predicates: .containing(...), intersecting(...), crossing(...)

Filters can be combined:

roads.ways("[bridge]").in(bbox).crossing(rhineRiver)

Work with individual features

Retrieve a feature’s tags:

Tags tags = feature.tags();
Map<String,Object> tagMap = feature.tags().toMap();

Get a specific tag value by key:

feature.stringValue("opening_hours") // returns empty string if tag not present
feature.intValue("maxspeed")         // 0 if tag not present or non-numeric

Get its type and ID:

FeatureType type = feature.type();   // NODE, WAY or RELATION
long osmId = feature.id();     

Its location:

feature.lon()  // degrees longitude
feature.lat()  // degrees latitude
feature.x()    // Mercator-projected X-coordinate
feature.y()    // Mercator-projected Y-coordinate

Its length (meters) or area (square meters):

feature.length()  // 0 if not linear
feature.area()    // 0 if not an area

Its JTS geometry:

feature.toGeometry()  // Point for a Node
                      // LineString or LinearRing for a non-area Way
                      // Polygon for a Way that represents an area
                      // Polygon or MultiPolygon for an area Relation
                      // GeometryCollection for all other Relations

Ways

Retrieve the nodes that make up a way:

way.nodes()             // all nodes    
way.nodes("[barrier]")  // only barriers

Or simply iterate the way:

for(var node: way) ... 

(Iteration only retrieves nodes that have tags or are part of a relation; nodes() returns all nodes).

Retrieve the ways to which a node belongs:

node.parents().ways()
node.parents("w[highway]")

Relations

Retrieve a relation’s members:

for(Feature member: rel.members())

Or simply iterate:

for(Feature member: rel) ...

Discover a member’s role:

member.role()   // "stop", "main_stream", etc.

Get the relations to which a feature belongs:

feature.parents().relations()    
feature.parents("r[route]")

Wrapping up

GeoDesk enables you to:

  • Create compact spatial databases (“Feature libraries”) based on OpenStreetMap data
  • Select features using a powerful query language and access their properties (“tags”) and geometries
  • Traverse the relationships between nodes, ways and relations
  • Leverage the Java Topology Suite for advanced geometric operations

Learn more