lukasmartinelli / osm-qa-filter

Extract GeoJSON features from OSM QA tiles
BSD 3-Clause "New" or "Revised" License
9 stars 2 forks source link

Unable to filter by $type #1

Closed robhawkes closed 6 years ago

robhawkes commented 7 years ago

Filtering by $type has no effect, resulting in a dataset containing either no features or all features regardless of geometry type.

The following filter:

osm-qa-filter -m united_kingdom.mbtiles -o uk.geojson --filter '["all", ["==", "amenity", "parking"], ["$type", "==", "Point"]]'

Results in a dataset containing both point and polygon geometries:

screen shot 2017-08-03 at 23 13 52

I've also tried swapping the filter ordering (["==", "$type", "Point"]) but that also doesn't work.

I'm able to replicate this for different OSM tags.

For this specific example I've been using the United Kingdom export of the OSM QA Tiles.

I tried swapping out the mapbox-gl-style-spec version of the feature_filter method with the latest mapbox-gl-js version but it still has the same issue.

robhawkes commented 7 years ago

I've had a dig into this as from what I can see the reason this isn't working is because features returned from the OSM QA Tiles MBTiles database don't contain a type property in the root feature object (which is what feature_filter is checking for), not inside the normal GeoJSON properties object (see the feature_filter example).

I don't even know if the OSM QA Tiles MBTiles data is meant to contain this property or if it's something that would need to be added within the mapping function based on the GeoJSON feature type. It's also worth mentioning that the type value is a number, not a string.

robhawkes commented 7 years ago

Ok I worked it out. Long story short is that feature_filter is expecting features in vector tile format, which is different to GeoJSON. This format already has the type property set to the correct value based on the geometry type.

There are two options…

The first is to keep the existing approach but switch out feature_filter for feature-filter-geojson. I've not tested if this works but it might do, though it's using a fork of feature_filter so it's already probably out of date.

The second is to convert osm-qa-filter to use vector features instead, which is pretty straightforward considering tile-reduce already does this (it's just disabled). By setting raw to true in the tile-reduce configuration this will be enabled. From there it's a case of re-working the map to use vector tiles:

'use strict';

const featureFilter = require('mapbox-gl-style-spec/lib/feature_filter');
const ff = featureFilter(global.mapOptions.filter)

module.exports = function(tileLayers, tile, write, done) {
  const layer = tileLayers.osm.osm;

  let features = [];
  for (var i = 0; i < layer.length; i++) {
    var ft = layer.feature(i);
    if (ff(ft)) {
      features.push(ft.toGeoJSON(tile[0], tile[1], tile[2]));
    }
  }

  features.forEach(function(feature) {
    write(JSON.stringify(feature) + '\n');
  });

  done(null, features.length);
};

I had to drop the fancy .filter() method but it works just as well. In fact, it runs over twice as fast using vector tile format!

Without the change (using GeoJSON):

$ osm-qa-filter -m united_kingdom.mbtiles -o uk.geojson --filter '["all", ["==", "amenity", "parking"], ["==", "$type", "Point"]]'
Starting up 8 workers... Job started.
Processing tile coords from "osm" source.
9134 tiles processed in 29s.
Total found features: 0

With the change (using vector tile format):

$ osm-qa-filter -m united_kingdom.mbtiles -o uk.geojson --filter '["all", ["==", "amenity", "parking"], ["==", "$type", "Point"]]'
Starting up 8 workers... Job started.
Processing tile coords from "osm" source.
9134 tiles processed in 13s.
Total found features: 15900
robhawkes commented 7 years ago

I've submitted PR #2 for this, I hope you don't mind.