underpass 0.0.6 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +428 -18
- data/lib/underpass/cache.rb +45 -0
- data/lib/underpass/client.rb +67 -0
- data/lib/underpass/configuration.rb +23 -0
- data/lib/underpass/errors.rb +15 -0
- data/lib/underpass/feature.rb +34 -0
- data/lib/underpass/filter.rb +56 -0
- data/lib/underpass/geo_json.rb +23 -0
- data/lib/underpass/matcher.rb +105 -0
- data/lib/underpass/ql/bounding_box.rb +19 -6
- data/lib/underpass/ql/builder.rb +97 -0
- data/lib/underpass/ql/query.rb +53 -7
- data/lib/underpass/ql/query_analyzer.rb +51 -0
- data/lib/underpass/ql/request.rb +45 -12
- data/lib/underpass/ql/response.rb +51 -0
- data/lib/underpass/shape.rb +118 -0
- data/lib/underpass/version.rb +2 -2
- data/lib/underpass/way_chain.rb +71 -0
- data/lib/underpass.rb +65 -19
- metadata +25 -42
- data/lib/underpass/ql/parser.rb +0 -56
- data/lib/underpass/ql/ql.rb +0 -15
- data/lib/underpass/ql/shape.rb +0 -35
data/lib/underpass/version.rb
CHANGED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Underpass
|
|
4
|
+
# Chains way node sequences that share endpoints into complete rings.
|
|
5
|
+
#
|
|
6
|
+
# Used internally by {Shape.multipolygon_from_relation} to merge multiple
|
|
7
|
+
# way segments into closed linear rings.
|
|
8
|
+
class WayChain
|
|
9
|
+
# @api private
|
|
10
|
+
MERGE_STRATEGIES = [
|
|
11
|
+
->(cur, seq) { cur.last == seq.first ? cur + seq[1..] : nil },
|
|
12
|
+
->(cur, seq) { cur.last == seq.last ? cur + seq.reverse[1..] : nil },
|
|
13
|
+
->(cur, seq) { cur.first == seq.last ? seq + cur[1..] : nil },
|
|
14
|
+
->(cur, seq) { cur.first == seq.first ? seq.reverse + cur[1..] : nil }
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
# Creates a new WayChain from way IDs and a way lookup table.
|
|
18
|
+
#
|
|
19
|
+
# @param way_ids [Array<Integer>] IDs of the ways to chain
|
|
20
|
+
# @param ways [Hash{Integer => Hash}] way lookup table
|
|
21
|
+
def initialize(way_ids, ways)
|
|
22
|
+
@sequences = way_ids.filter_map do |way_id|
|
|
23
|
+
way = ways[way_id]
|
|
24
|
+
next unless way
|
|
25
|
+
|
|
26
|
+
way[:nodes].dup
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Merges node sequences that share endpoints into continuous rings.
|
|
31
|
+
#
|
|
32
|
+
# @return [Array<Array<Integer>>] the merged node ID sequences
|
|
33
|
+
def merged_sequences
|
|
34
|
+
return @sequences if @sequences.empty?
|
|
35
|
+
|
|
36
|
+
remaining = @sequences.dup
|
|
37
|
+
current = remaining.shift
|
|
38
|
+
current, remaining = merge_all(current, remaining)
|
|
39
|
+
[current, *remaining]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def merge_all(current, remaining)
|
|
45
|
+
until remaining.empty?
|
|
46
|
+
found = find_connection(current, remaining)
|
|
47
|
+
break unless found
|
|
48
|
+
|
|
49
|
+
remaining.delete(found[:seq])
|
|
50
|
+
current = found[:merged]
|
|
51
|
+
end
|
|
52
|
+
[current, remaining]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def find_connection(current, sequences)
|
|
56
|
+
sequences.each do |seq|
|
|
57
|
+
merged = try_merge(current, seq)
|
|
58
|
+
return { seq: seq, merged: merged } if merged
|
|
59
|
+
end
|
|
60
|
+
nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def try_merge(current, seq)
|
|
64
|
+
MERGE_STRATEGIES.each do |strategy|
|
|
65
|
+
result = strategy.call(current, seq)
|
|
66
|
+
return result if result
|
|
67
|
+
end
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
data/lib/underpass.rb
CHANGED
|
@@ -3,26 +3,72 @@
|
|
|
3
3
|
require 'rgeo'
|
|
4
4
|
require 'json'
|
|
5
5
|
|
|
6
|
-
require 'underpass/
|
|
6
|
+
require 'underpass/cache'
|
|
7
|
+
require 'underpass/configuration'
|
|
8
|
+
require 'underpass/errors'
|
|
9
|
+
require 'underpass/client'
|
|
10
|
+
require 'underpass/feature'
|
|
11
|
+
require 'underpass/filter'
|
|
12
|
+
require 'underpass/geo_json'
|
|
13
|
+
require 'underpass/matcher'
|
|
14
|
+
require 'underpass/shape'
|
|
15
|
+
require 'underpass/way_chain'
|
|
16
|
+
require 'underpass/ql/bounding_box'
|
|
17
|
+
require 'underpass/ql/builder'
|
|
18
|
+
require 'underpass/ql/query'
|
|
19
|
+
require 'underpass/ql/query_analyzer'
|
|
20
|
+
require 'underpass/ql/request'
|
|
21
|
+
require 'underpass/ql/response'
|
|
7
22
|
|
|
8
23
|
# Underpass is a library that makes it easy to query the Overpass API
|
|
9
|
-
# and translate its responses into RGeo objects
|
|
24
|
+
# and translate its responses into RGeo objects.
|
|
25
|
+
#
|
|
26
|
+
# @example Quick start
|
|
27
|
+
# wkt = 'POLYGON ((23.669 47.65, 23.725 47.65, 23.725 47.674, 23.669 47.674, 23.669 47.65))'
|
|
28
|
+
# bbox = RGeo::Geographic.spherical_factory.parse_wkt(wkt)
|
|
29
|
+
# query = 'way["heritage:operator"="lmi"];'
|
|
30
|
+
# features = Underpass::QL::Query.perform(bbox, query)
|
|
31
|
+
#
|
|
32
|
+
# @example Configure the API endpoint
|
|
33
|
+
# Underpass.configure do |config|
|
|
34
|
+
# config.api_endpoint = 'https://overpass.kumi.systems/api/interpreter'
|
|
35
|
+
# config.timeout = 30
|
|
36
|
+
# end
|
|
10
37
|
module Underpass
|
|
11
|
-
|
|
38
|
+
class << self
|
|
39
|
+
# @return [Cache, nil] the cache instance used for storing API responses
|
|
40
|
+
attr_accessor :cache
|
|
12
41
|
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
42
|
+
# @return [Configuration] the current configuration
|
|
43
|
+
attr_writer :configuration
|
|
44
|
+
|
|
45
|
+
# Returns the current configuration, initializing a default one if needed.
|
|
46
|
+
#
|
|
47
|
+
# @return [Configuration] the current configuration
|
|
48
|
+
def configuration
|
|
49
|
+
@configuration ||= Configuration.new
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Yields the current configuration for modification.
|
|
53
|
+
#
|
|
54
|
+
# @yield [config] the current configuration
|
|
55
|
+
# @yieldparam config [Configuration] the configuration instance
|
|
56
|
+
# @return [void]
|
|
57
|
+
#
|
|
58
|
+
# @example
|
|
59
|
+
# Underpass.configure do |config|
|
|
60
|
+
# config.api_endpoint = 'https://overpass.kumi.systems/api/interpreter'
|
|
61
|
+
# config.timeout = 30
|
|
62
|
+
# end
|
|
63
|
+
def configure
|
|
64
|
+
yield(configuration)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Resets the configuration to default values.
|
|
68
|
+
#
|
|
69
|
+
# @return [Configuration] a new default configuration
|
|
70
|
+
def reset_configuration!
|
|
71
|
+
@configuration = Configuration.new
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
metadata
CHANGED
|
@@ -1,69 +1,42 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: underpass
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Janos Rusiczki
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rgeo
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
|
-
- - ">="
|
|
18
|
-
- !ruby/object:Gem::Version
|
|
19
|
-
version: 2.0.0
|
|
20
16
|
- - "~>"
|
|
21
17
|
- !ruby/object:Gem::Version
|
|
22
|
-
version: '
|
|
18
|
+
version: '3.1'
|
|
23
19
|
type: :runtime
|
|
24
20
|
prerelease: false
|
|
25
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
26
22
|
requirements:
|
|
27
|
-
- - ">="
|
|
28
|
-
- !ruby/object:Gem::Version
|
|
29
|
-
version: 2.0.0
|
|
30
23
|
- - "~>"
|
|
31
24
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: '
|
|
25
|
+
version: '3.1'
|
|
33
26
|
- !ruby/object:Gem::Dependency
|
|
34
|
-
name:
|
|
27
|
+
name: rgeo-geojson
|
|
35
28
|
requirement: !ruby/object:Gem::Requirement
|
|
36
29
|
requirements:
|
|
37
|
-
- - ">="
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: 3.8.0
|
|
40
30
|
- - "~>"
|
|
41
31
|
- !ruby/object:Gem::Version
|
|
42
|
-
version: '
|
|
43
|
-
type: :
|
|
44
|
-
prerelease: false
|
|
45
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
46
|
-
requirements:
|
|
47
|
-
- - ">="
|
|
48
|
-
- !ruby/object:Gem::Version
|
|
49
|
-
version: 3.8.0
|
|
50
|
-
- - "~>"
|
|
51
|
-
- !ruby/object:Gem::Version
|
|
52
|
-
version: '3.8'
|
|
53
|
-
- !ruby/object:Gem::Dependency
|
|
54
|
-
name: simplecov
|
|
55
|
-
requirement: !ruby/object:Gem::Requirement
|
|
56
|
-
requirements:
|
|
57
|
-
- - "~>"
|
|
58
|
-
- !ruby/object:Gem::Version
|
|
59
|
-
version: 0.16.0
|
|
60
|
-
type: :development
|
|
32
|
+
version: '2.2'
|
|
33
|
+
type: :runtime
|
|
61
34
|
prerelease: false
|
|
62
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
63
36
|
requirements:
|
|
64
37
|
- - "~>"
|
|
65
38
|
- !ruby/object:Gem::Version
|
|
66
|
-
version:
|
|
39
|
+
version: '2.2'
|
|
67
40
|
description: " A library that makes it easy to query the Overpass API and translate
|
|
68
41
|
its responses into RGeo objects\n"
|
|
69
42
|
email: janos.rusiczki@gmail.com
|
|
@@ -74,20 +47,31 @@ files:
|
|
|
74
47
|
- LICENSE
|
|
75
48
|
- README.md
|
|
76
49
|
- lib/underpass.rb
|
|
50
|
+
- lib/underpass/cache.rb
|
|
51
|
+
- lib/underpass/client.rb
|
|
52
|
+
- lib/underpass/configuration.rb
|
|
53
|
+
- lib/underpass/errors.rb
|
|
54
|
+
- lib/underpass/feature.rb
|
|
55
|
+
- lib/underpass/filter.rb
|
|
56
|
+
- lib/underpass/geo_json.rb
|
|
57
|
+
- lib/underpass/matcher.rb
|
|
77
58
|
- lib/underpass/ql/bounding_box.rb
|
|
78
|
-
- lib/underpass/ql/
|
|
79
|
-
- lib/underpass/ql/ql.rb
|
|
59
|
+
- lib/underpass/ql/builder.rb
|
|
80
60
|
- lib/underpass/ql/query.rb
|
|
61
|
+
- lib/underpass/ql/query_analyzer.rb
|
|
81
62
|
- lib/underpass/ql/request.rb
|
|
82
|
-
- lib/underpass/ql/
|
|
63
|
+
- lib/underpass/ql/response.rb
|
|
64
|
+
- lib/underpass/shape.rb
|
|
83
65
|
- lib/underpass/version.rb
|
|
66
|
+
- lib/underpass/way_chain.rb
|
|
84
67
|
homepage: http://github.com/haiafara/underpass
|
|
85
68
|
licenses:
|
|
86
69
|
- MIT
|
|
87
70
|
metadata:
|
|
88
71
|
source_code_uri: http://github.com/haiafara/underpass
|
|
89
72
|
bug_tracker_uri: http://github.com/haiafara/underpass/issues
|
|
90
|
-
|
|
73
|
+
documentation_uri: https://haiafara.github.io/underpass
|
|
74
|
+
rubygems_mfa_required: 'true'
|
|
91
75
|
rdoc_options: []
|
|
92
76
|
require_paths:
|
|
93
77
|
- lib
|
|
@@ -95,15 +79,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
95
79
|
requirements:
|
|
96
80
|
- - ">="
|
|
97
81
|
- !ruby/object:Gem::Version
|
|
98
|
-
version:
|
|
82
|
+
version: 3.4.0
|
|
99
83
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
84
|
requirements:
|
|
101
85
|
- - ">="
|
|
102
86
|
- !ruby/object:Gem::Version
|
|
103
87
|
version: '0'
|
|
104
88
|
requirements: []
|
|
105
|
-
rubygems_version: 3.
|
|
106
|
-
signing_key:
|
|
89
|
+
rubygems_version: 3.6.9
|
|
107
90
|
specification_version: 4
|
|
108
91
|
summary: A library that translates Overpass API responses into RGeo objects
|
|
109
92
|
test_files: []
|
data/lib/underpass/ql/parser.rb
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Underpass
|
|
4
|
-
module QL
|
|
5
|
-
# Deals with parsing the API request response into easily digestable objects
|
|
6
|
-
# which are then returned as matches
|
|
7
|
-
class Parser
|
|
8
|
-
def initialize(response)
|
|
9
|
-
@response = response
|
|
10
|
-
@matches = []
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def parse
|
|
14
|
-
parsed_json = JSON.parse(@response.body, symbolize_names: true)
|
|
15
|
-
elements = parsed_json[:elements]
|
|
16
|
-
|
|
17
|
-
@nodes = extract_indexed_nodes(elements)
|
|
18
|
-
@ways = extract_indexed_ways(elements)
|
|
19
|
-
|
|
20
|
-
self
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def matches
|
|
24
|
-
@nodes.each_value do |node|
|
|
25
|
-
@matches << point_from_node(node) if node.key?(:tags)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
@ways.each_value do |way|
|
|
29
|
-
@matches << polygon_from_way(way, @nodes) if way.key?(:tags)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
@matches
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
private
|
|
36
|
-
|
|
37
|
-
def point_from_node(node)
|
|
38
|
-
Underpass::QL::Shape.point_from_node(node)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def polygon_from_way(way, nodes)
|
|
42
|
-
Underpass::QL::Shape.polygon_from_way(way, nodes)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def extract_indexed_nodes(elements)
|
|
46
|
-
nodes = elements.select { |e| e[:type] == 'node' }
|
|
47
|
-
nodes.map { |e| [e[:id], e] }.to_h
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def extract_indexed_ways(elements)
|
|
51
|
-
ways = elements.select { |e| e[:type] == 'way' }
|
|
52
|
-
ways.map { |e| [e[:id], e] }.to_h
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
data/lib/underpass/ql/ql.rb
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'underpass/ql/bounding_box'
|
|
4
|
-
require 'underpass/ql/shape'
|
|
5
|
-
require 'underpass/ql/request'
|
|
6
|
-
require 'underpass/ql/parser'
|
|
7
|
-
require 'underpass/ql/query'
|
|
8
|
-
|
|
9
|
-
module Underpass
|
|
10
|
-
# Provides the means to work with Overpass by using the
|
|
11
|
-
# Overpass Query Language (QL). Overpass also provides an XML based
|
|
12
|
-
# query language but we're not interested in that
|
|
13
|
-
module QL
|
|
14
|
-
end
|
|
15
|
-
end
|
data/lib/underpass/ql/shape.rb
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Underpass
|
|
4
|
-
module QL
|
|
5
|
-
# Contains factories for various RGeo shapes from ways and nodes parsed
|
|
6
|
-
# with the Parser class
|
|
7
|
-
class Shape
|
|
8
|
-
def self.polygon_from_way(way, nodes)
|
|
9
|
-
f = RGeo::Geographic.spherical_factory(srid: 4326)
|
|
10
|
-
f.polygon(line_string_from_way(way, nodes))
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def self.line_string_from_way(way, nodes)
|
|
14
|
-
f = RGeo::Geographic.spherical_factory(srid: 4326)
|
|
15
|
-
f.line_string(
|
|
16
|
-
way[:nodes].map do |n|
|
|
17
|
-
f.point(nodes[n][:lon], nodes[n][:lat])
|
|
18
|
-
end
|
|
19
|
-
)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def self.point_from_node(node)
|
|
23
|
-
f = RGeo::Geographic.spherical_factory(srid: 4326)
|
|
24
|
-
f.point(node[:lon], node[:lat])
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# There should be some sort of 'decorator' to return an object
|
|
28
|
-
# with the shape and a copy of the tags as
|
|
29
|
-
# {
|
|
30
|
-
# tags: way[:tags],
|
|
31
|
-
# shape: shape
|
|
32
|
-
# }
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|