module Underpass
class Matcher
def initialize(response, requested_types = nil)
@nodes = response.nodes
@ways = response.ways
@relations = response.relations
@requested_types = requested_types || %w[node way relation]
end
def matches
@matches ||= lazy_matches.to_a
end
def lazy_matches
tagged_elements.lazy.flat_map { |element| features_for(element) }
end
private
def tagged_elements
elements = []
elements.concat(@nodes.values.select { |n| n.key?(:tags) }) if @requested_types.include?('node')
elements.concat(@ways.values.select { |w| w.key?(:tags) }) if @requested_types.include?('way')
elements.concat(@relations.values.select { |r| r.key?(:tags) }) if @requested_types.include?('relation')
elements
end
def features_for(element)
case element[:type]
when 'node'
[build_feature(Shape.point_from_node(element), element)]
when 'way'
[build_feature(way_geometry(element), element)]
when 'relation'
relation_features(element)
else
[]
end
end
def relation_features(relation)
geometry = relation_geometry(relation)
if geometry.is_a?(Array)
geometry.map { |g| build_feature(g, relation) }
else
[build_feature(geometry, relation)]
end
end
def relation_geometry(relation)
case relation[:tags][:type]
when 'multipolygon'
Shape.multipolygon_from_relation(relation, @ways, @nodes)
when 'route'
Shape.multi_line_string_from_relation(relation, @ways, @nodes)
else
expand_relation_members(relation)
end
end
def expand_relation_members(relation)
relation[:members].filter_map do |member|
case member[:type]
when 'node' then Shape.point_from_node(@nodes[member[:ref]])
when 'way' then way_geometry(@ways[member[:ref]])
end
end
end
def way_geometry(way)
if Shape.open_way?(way)
Shape.polygon_from_way(way, @nodes)
else
Shape.line_string_from_way(way, @nodes)
end
end
def build_feature(geometry, element)
Feature.new(
geometry: geometry,
properties: element[:tags] || {},
id: element[:id],
type: element[:type]
)
end
end
end