Skip to content

Commit

Permalink
Merge pull request #244 from lonvia/filters
Browse files Browse the repository at this point in the history
Introduce filter handlers
  • Loading branch information
lonvia authored Mar 10, 2024
2 parents 0f336d3 + 67e4254 commit 5e231e4
Show file tree
Hide file tree
Showing 20 changed files with 456 additions and 50 deletions.
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,16 @@ pybind11_add_module(_replication lib/replication.cc)
set_module_output(_replication osmium/replication)
pybind11_add_module(_area lib/area.cc)
set_module_output(_area osmium/area)

pybind11_add_module(_filter
lib/filter.cc
lib/empty_tag_filter.cc
lib/key_filter.cc)
set_module_output(_filter osmium/filter)

target_link_libraries(_osmium PRIVATE ${OSMIUM_LIBRARIES})
target_link_libraries(_replication PRIVATE ${OSMIUM_LIBRARIES})
target_link_libraries(_area PRIVATE ${OSMIUM_LIBRARIES})
target_link_libraries(_filter PRIVATE ${OSMIUM_LIBRARIES})

# workaround for https://github.com/pybind/pybind11/issues/1272
if(APPLE)
Expand Down
14 changes: 6 additions & 8 deletions examples/amenity_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,20 @@ def print_amenity(self, tags, lon, lat):
print("%f %f %-15s %s" % (lon, lat, tags['amenity'], name))

def node(self, n):
if 'amenity' in n.tags:
self.print_amenity(n.tags, n.location.lon, n.location.lat)
self.print_amenity(n.tags, n.location.lon, n.location.lat)

def area(self, a):
if 'amenity' in a.tags:
wkb = wkbfab.create_multipolygon(a)
poly = wkblib.loads(wkb, hex=True)
centroid = poly.representative_point()
self.print_amenity(a.tags, centroid.x, centroid.y)
wkb = wkbfab.create_multipolygon(a)
poly = wkblib.loads(wkb, hex=True)
centroid = poly.representative_point()
self.print_amenity(a.tags, centroid.x, centroid.y)


def main(osmfile):

handler = AmenityListHandler()

handler.apply_file(osmfile)
handler.apply_file(osmfile, filters=[o.filter.KeyFilter('amenity')])

return 0

Expand Down
12 changes: 8 additions & 4 deletions lib/area.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,22 @@ class AreaManagerSecondPassHandler : public BaseHandler
{ osmium::apply(ab, this->m_handlers); });
}

void node(osmium::Node const *n) override
bool node(osmium::Node const *n) override
{
m_mp_manager->handle_node(*n);
return false;
}

void way(osmium::Way *w) override
bool way(osmium::Way *w) override
{
m_mp_manager->handle_way(*w);
return false;
}

void relation(osmium::Relation const *r) override
bool relation(osmium::Relation const *r) override
{
m_mp_manager->handle_relation(*r);
return false;
}

void flush() override
Expand All @@ -67,9 +70,10 @@ class AreaManager : public BaseHandler
BaseHandler *first_pass_handler() { return this; }

// first-pass-handler
void relation(osmium::Relation const *r) override
bool relation(osmium::Relation const *r) override
{
m_mp_manager.relation(*r);
return false;
}

AreaManagerSecondPassHandler *second_pass_handler(py::args args)
Expand Down
76 changes: 76 additions & 0 deletions lib/base_filter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: BSD-2-Clause
*
* This file is part of pyosmium. (https://osmcode.org/pyosmium/)
*
* Copyright (C) 2024 Sarah Hoffmann <[email protected]> and others.
* For a full list of authors see the git log.
*/
#ifndef PYOSMIUM_BASE_FILTER_HPP
#define PYOSMIUM_BASE_FILTER_HPP

#include <osmium/osm.hpp>
#include <osmium/osm/entity_bits.hpp>

#include "base_handler.h"

namespace pyosmium {

class BaseFilter : public BaseHandler {
public:
bool node(osmium::Node const *n) override
{
return (m_enabled_for & osmium::osm_entity_bits::node)
&& filter_node(n);
}

bool way(osmium::Way *n) override
{
return (m_enabled_for & osmium::osm_entity_bits::way)
&& filter_way(n);
}

bool relation(osmium::Relation const *n) override
{
return (m_enabled_for & osmium::osm_entity_bits::relation)
&& filter_relation(n);
}

bool area(osmium::Area const *n) override
{
return (m_enabled_for & osmium::osm_entity_bits::area)
&& filter_area(n);
}

bool changeset(osmium::Changeset const *n) override
{
return (m_enabled_for & osmium::osm_entity_bits::changeset)
&& filter_changeset(n);
}

BaseFilter *enable_for(osmium::osm_entity_bits::type entities)
{
m_enabled_for = entities;
return this;
}

protected:
virtual bool filter(osmium::OSMObject const *) { return false; }
virtual bool filter_node(osmium::Node const *n) { return filter(n); }
virtual bool filter_way(osmium::Way const *w) { return filter(w); }
virtual bool filter_relation(osmium::Relation const *r) { return filter(r); }
virtual bool filter_area(osmium::Area const *a) { return filter(a); }
virtual bool filter_changeset(osmium::Changeset const *) { return false; }

private:
osmium::osm_entity_bits::type m_enabled_for = osmium::osm_entity_bits::all;

};


void init_empty_tag_filter(pybind11::module &m);
void init_key_filter(pybind11::module &m);

} // namespace


#endif //PYOSMIUM_BASE_FILTER_HPP
15 changes: 9 additions & 6 deletions lib/base_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ class BaseHandler : public osmium::handler::Handler
void changeset(const osmium::Changeset &o) { changeset(&o); }
void area(const osmium::Area &o) { area(&o); }

// actual handler functions
virtual void node(const osmium::Node*) {}
virtual void way(osmium::Way *) {}
virtual void relation(const osmium::Relation*) {}
virtual void changeset(const osmium::Changeset*) {}
virtual void area(const osmium::Area*) {}
// Actual handler functions.
// All object handlers return a boolean which indicates if
// processing is finished (true) or should be continued with the next
// handler (false).
virtual bool node(const osmium::Node*) { return false; }
virtual bool way(osmium::Way *) { return false; }
virtual bool relation(const osmium::Relation*) { return false; }
virtual bool changeset(const osmium::Changeset*) { return false; }
virtual bool area(const osmium::Area*) { return false; }

virtual void flush() {}
};
Expand Down
43 changes: 43 additions & 0 deletions lib/empty_tag_filter.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* SPDX-License-Identifier: BSD-2-Clause
*
* This file is part of pyosmium. (https://osmcode.org/pyosmium/)
*
* Copyright (C) 2024 Sarah Hoffmann <[email protected]> and others.
* For a full list of authors see the git log.
*/
#include <pybind11/pybind11.h>

#include <osmium/osm.hpp>

#include "base_filter.h"

namespace py = pybind11;

namespace {

class EmptyTagFilter : public pyosmium::BaseFilter
{
bool filter(osmium::OSMObject const *o) override
{
return o->tags().empty();
}

bool filter_changeset(osmium::Changeset const *o) override
{
return o->tags().empty();
}

};

}

namespace pyosmium {

void init_empty_tag_filter(pybind11::module &m)
{
py::class_<EmptyTagFilter, pyosmium::BaseFilter, BaseHandler>(m, "EmptyTagFilter")
.def(py::init<>())
;
}

} // namespace
25 changes: 25 additions & 0 deletions lib/filter.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: BSD-2-Clause
*
* This file is part of pyosmium. (https://osmcode.org/pyosmium/)
*
* Copyright (C) 2024 Sarah Hoffmann <[email protected]> and others.
* For a full list of authors see the git log.
*/
#include <pybind11/pybind11.h>

#include "base_filter.h"


namespace py = pybind11;

PYBIND11_MODULE(_filter, m) {
py::class_<pyosmium::BaseFilter, BaseHandler>(m, "BaseFilter")
.def("enable_for", &pyosmium::BaseFilter::enable_for,
py::arg("entities"),
"Set the OSM types this filter should be used for.")
;

pyosmium::init_empty_tag_filter(m);
pyosmium::init_key_filter(m);
};

20 changes: 15 additions & 5 deletions lib/handler_chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,31 +45,41 @@ class HandlerChain : public osmium::handler::Handler

void node(osmium::Node const &o) {
for (auto const &handler : m_handlers) {
handler->node(&o);
if (handler->node(&o)) {
return;
}
}
}

void way(osmium::Way &w) {
for (auto const &handler : m_handlers) {
handler->way(&w);
if (handler->way(&w)) {
return;
}
}
}

void relation(osmium::Relation const &o) {
for (auto const &handler : m_handlers) {
handler->relation(&o);
if (handler->relation(&o)) {
return;
}
}
}

void changeset(osmium::Changeset const &o) {
for (auto const &handler : m_handlers) {
handler->changeset(&o);
if (handler->changeset(&o)) {
return;
}
}
}

void area(osmium::Area const &o) {
for (auto const &handler : m_handlers) {
handler->area(&o);
if (handler->area(&o)) {
return;
}
}
}

Expand Down
76 changes: 76 additions & 0 deletions lib/key_filter.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: BSD-2-Clause
*
* This file is part of pyosmium. (https://osmcode.org/pyosmium/)
*
* Copyright (C) 2024 Sarah Hoffmann <[email protected]> and others.
* For a full list of authors see the git log.
*/
#include <pybind11/pybind11.h>

#include <osmium/osm.hpp>

#include "base_filter.h"

namespace py = pybind11;

namespace {

class KeyFilter : public pyosmium::BaseFilter
{
public:
KeyFilter(py::args args)
{
if (args.empty()) {
throw py::type_error{"Need keys to filter on."};
}

m_keys.reserve(args.size());
for (auto const &arg: args) {
if (!py::isinstance<py::str>(arg)) {
throw py::type_error{"Arguments must be strings."};
}

m_keys.push_back(arg.cast<std::string>());
}
}

bool filter(osmium::OSMObject const *o) override
{
auto const &tags = o->tags();
for (auto const &key: m_keys) {
if (tags.has_key(key.c_str())) {
return false;
}
}

return true;
}

bool filter_changeset(osmium::Changeset const *o) override
{
auto const &tags = o->tags();
for (auto const &key: m_keys) {
if (tags.has_key(key.c_str())) {
return false;
}
}

return true;
}

private:
std::vector<std::string> m_keys;
};

}

namespace pyosmium {

void init_key_filter(pybind11::module &m)
{
py::class_<KeyFilter, pyosmium::BaseFilter, BaseHandler>(m, "KeyFilter")
.def(py::init<py::args>())
;
}

} // namespace
6 changes: 4 additions & 2 deletions lib/node_location_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ class NodeLocationsForWays : public BaseHandler
: handler(idx)
{}

void node(const osmium::Node *o) override
bool node(const osmium::Node *o) override
{
handler.node(*o);
return false;
}

void way(osmium::Way *o) override
bool way(osmium::Way *o) override
{
if (apply_nodes_to_ways) {
handler.way(*o);
}
return false;
}

bool get_apply_nodes_to_ways() const { return apply_nodes_to_ways; }
Expand Down
Loading

0 comments on commit 5e231e4

Please sign in to comment.