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

Queries and Feature Collections

Geospatial applications typically work with subsets of features in a library, such as buildings in a town, or waterways in a particular region. These subsets are represented as feature collections, which are the result of queries.

  • Feature collections are lightweight objects that merely described what should be returned; they don’t actually contain any objects and take up minimal space. In other words, query execution is lazy: Features are fetched only once they are needed, in response to iteration or a call to count().

  • Feature collections can be ordered or unordered. Only the nodes of a way and the members of a relation are ordered; all other query results are returned in arbitrary order.

Start working with collections by creating a root collection, which contains all features in a given Geographic Object Library:

Features(const char* golFileName);

From this collection, you can create others:

Features france("path/to/france.gol");
...
Features shops = france("na[shop]");
Features thingsInParis = france(paris);  // Feature or geometry 
Features shopsInParis = shops & thingsInParis;

Filtering features

To select a subset of Features, add the constraint in parentheses, or apply a filter method. This always creates a new collection, leaving the original Features object unmodified.

By bounding box

Select the features whose bounding boxes intersect the given Box:

Features france("france.gol");
Box parisBounds = Box::ofWSEN(
    2.2, 48.8, 2.5, 48.9);
Features thingsInParis = france(parisBounds);

By type and tags

Apply a query written in GOQL (Geographic Object Query Language) to select features based on their type and tags:

Features restaurants = world(
    "na[amenity=restaurant]");   
    // nodes and areas
    
Nodes fireHydrants = world(
    "n[emergency=fire_hydrant]");
    // only nodes
    
Ways safeForCycling = world(
    "w[highway=cycleway,path,living_street],"        
    "w[highway][maxspeed < 30]");
    // linear ways

Using filter methods

Apply a spatial filter or topological filter, or a custom filter:

states.within(usa)
features("w[highway]").membersOf(route66)
parks.filter(MyFilters::containsWaterFountains);

Using set intersection

Select only features that are in both sets:

Features museums = world("na[tourism=museum]");
Features inParis = world.within(paris);
Features parisMuseums = museums(inParis);

Alternatively, you can use the & operator:

Features parisMuseums = museums & inParis;

Obtaining Feature objects

Simply iterate:

for(Feature hotel : hotels)
{
    std::cout << hotel["name"] << std::endl;
}

Create a std::vector, or populate an existing one:

std::vector<Feature> list = streets;
streets.addTo(myVector);

Check if the set is empty:

if (pubs.within(dublin))
    printf("Great, we can grab a beer in this town!");

if (!street.nodes("[traffic_calming=bump]"))
    printf("No speed bumps on this street.");

Obtaining a single Feature

first

Returns the first feature in a collection:

std::optional<Feature> city = france("n[place=city][name=Paris]").first();

Note that only the nodes of ways and members of relations are ordered collections; all others are unordered sets, which means you’ll receive a random feature if there are more than one. If the collection is empty, first() returns nullopt.

one

Returns the one and only feature of the collection. Throws a QueryException if the collection is empty or contains more than one feature.

Feature paris = world("n[place=city][name=Paris]").one();
    // will likely throw a QueryException, 
    // because there's also Paris, Texas

Testing for membership

To check if a feature belongs to a given set, use contains():

Features sushiRestaurants = 
    world("na[amenity=restaurant][cuisine=sushi]");

if (sushiRestaurants.contains(restaurant))
    std::cout << restaurant["name"] << " serves sushi";

Scalar queries

count

The total number of features in the collection:

printf("%d restaurants found.", restaurants.count());

area

The total area (square meters as double) of all areas in this set.

printf("London has %f square meters of parks.", 
    parks.within(london).area());

length

The total length (meters as double) of all features in this set. For areas, their circumference is used.

printf("The French motorway network is %f km long.", 
    france("w[highway=motorway]").length() / 1000);

Spatial filters

Features can be filtered by their spatial relationship to other geometric objects (typically a GEOSGeometry or another Feature).

containing

Selects features whose geometry contains A:

  • Every point of A is a point of the candidate feature, and the interiors of the two geometries have at least one point in common.
Features containing(Feature);
Features containing(GEOSGeometry);
Features containingXY(Coordinate);
Features containingLonLat(double, double);

For example:

// In which park (if any) is this statue of Claude Monet?
return features("a[leisure=park]")
    .containing(statueOfMonet).first();

// The county, state and country for this point -- should return 
// San Diego County, California, USA (in no particular order)  
return features("a[boundary=administrative][admin_level <= 6]")
    .containingLonLat(-117.25, 32.99); 

coveredBy

Selects features whose geometry is covered by A:

  • No point of the candidate feature’s geometry lies outside of A.
Features coveredBy(Feature);
Features coveredBy(GEOSGeometry);

crossing

Selects features whose geometry crosses A:

  • The geometries of A and the candidate feature have some (but not all) interior points in common
  • The dimension of the intersection must be less than the maximum dimension of the candidate and A.
Features crossing(Feature);
Features crossing(GEOSGeometry);

For example:

// All railway bridges across the Mississippi River
Features railwayBridges = features("w[railway][bridge]");    
return railwayBridges.crossing(mississippi);

intersecting

Selects features whose geometry intersects A:

  • The geometries of A and the candidate feature have at least one point in common.
Features intersecting(Feature);
Features intersecting(GEOSGeometry);

maxMetersFrom

Selects features whose distance to A is less or equal to m meters (measured between the closest points of the candidate feature and A).

Features maxMetersFrom(double, Feature);
Features maxMetersFrom(double, GEOSGeometry);
Features maxMetersFrom(double, Coordinate);
Features maxMetersFromLonLat(double, double, double);

For example:

// All bus stops within 500 meters of the given restaurant
Features nearbyBusStops = features("n[highway=bus_stop]")
    .maxMetersFrom(500, restaurant);
 
// All features within 3 km of the given point 
return features.maxMetersFromLonLat(3000, 76.41, 40.12); 

within

Selects features that lie entirely within A:

  • Every point of the candidate feature is a point in A, and their interiors have at least one point in common.
Features within(Feature);
Features within(GEOSGeometry);

Topological filters

These methods return a subset of those features that have a specific topological relationship with another Feature.

connectedTo

Selects all features that have at least one node (vertex) in common with the given Feature or Geometry.

Features connectedTo(Feature);
Features connectedTo(GEOSGeometry);

nodesOf

The nodes of the given way. Returns an empty set if the feature is a Node or Relation.

Nodes nodesOf(Feature);

membersOf

Features that are members of the given relation, or nodes of the given way. Returns an empty set if the feature is a Node.

Features membersOf(Feature);

parentsOf

Relations that have the given feature as a member, as well as ways to which the given node belongs.

Features parentsOf(Feature);

Custom filters

Use filter() with your own filter predicate:

// Find all parks whose area is at least 1 km²
// (one million square meters)
 
Features parks = world("a[leisure=park]");
Features largeParks = parks.filter([](Feature park)
    { return park.area() > 1'000'000; });

Important: The predicate must be threadsafe, as the query may be executed in parallel.