underpass 0.0.7 → 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.
@@ -12,8 +12,8 @@ module Underpass
12
12
  # Used to generate the version string
13
13
  module VERSION
14
14
  MAJOR = 0
15
- MINOR = 0
16
- PATCH = 7
15
+ MINOR = 9
16
+ PATCH = 0
17
17
 
18
18
  STRING = [MAJOR, MINOR, PATCH].join('.')
19
19
  end
@@ -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/ql/ql'
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
- end
38
+ class << self
39
+ # @return [Cache, nil] the cache instance used for storing API responses
40
+ attr_accessor :cache
12
41
 
13
- # Example usage
14
- #
15
- # require 'underpass'
16
- # wkt = <<-WKT
17
- # POLYGON ((
18
- # 23.669 47.65,
19
- # 23.725 47.65,
20
- # 23.725 47.674,
21
- # 23.669 47.674,
22
- # 23.669 47.65
23
- # ))
24
- # WKT
25
- # f = RGeo::Geographic.spherical_factory
26
- # bbox = f.parse_wkt(wkt)
27
- # op_query = 'way["heritage:operator"="lmi"]["ref:ro:lmi"="MM-II-m-B-04508"];'
28
- # Underpass::QL::Query.perform(bbox, op_query)
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,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: underpass
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
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: 2019-05-03 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rgeo
@@ -16,114 +15,28 @@ dependencies:
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '2.0'
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: 2.0.0
18
+ version: '3.1'
23
19
  type: :runtime
24
20
  prerelease: false
25
21
  version_requirements: !ruby/object:Gem::Requirement
26
22
  requirements:
27
23
  - - "~>"
28
24
  - !ruby/object:Gem::Version
29
- version: '2.0'
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: 2.0.0
33
- - !ruby/object:Gem::Dependency
34
- name: guard
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: 2.15.0
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: 2.15.0
43
- type: :development
44
- prerelease: false
45
- version_requirements: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - "~>"
48
- - !ruby/object:Gem::Version
49
- version: 2.15.0
50
- - - ">="
51
- - !ruby/object:Gem::Version
52
- version: 2.15.0
53
- - !ruby/object:Gem::Dependency
54
- name: guard-rspec
55
- requirement: !ruby/object:Gem::Requirement
56
- requirements:
57
- - - "~>"
58
- - !ruby/object:Gem::Version
59
- version: 4.7.3
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- version: 4.7.3
63
- type: :development
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - "~>"
68
- - !ruby/object:Gem::Version
69
- version: 4.7.3
70
- - - ">="
71
- - !ruby/object:Gem::Version
72
- version: 4.7.3
25
+ version: '3.1'
73
26
  - !ruby/object:Gem::Dependency
74
- name: guard-rubocop
27
+ name: rgeo-geojson
75
28
  requirement: !ruby/object:Gem::Requirement
76
29
  requirements:
77
30
  - - "~>"
78
31
  - !ruby/object:Gem::Version
79
- version: 1.3.0
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: 1.3.0
83
- type: :development
84
- prerelease: false
85
- version_requirements: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 1.3.0
90
- - - ">="
91
- - !ruby/object:Gem::Version
92
- version: 1.3.0
93
- - !ruby/object:Gem::Dependency
94
- name: rspec
95
- requirement: !ruby/object:Gem::Requirement
96
- requirements:
97
- - - "~>"
98
- - !ruby/object:Gem::Version
99
- version: '3.8'
100
- - - ">="
101
- - !ruby/object:Gem::Version
102
- version: 3.8.0
103
- type: :development
104
- prerelease: false
105
- version_requirements: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - "~>"
108
- - !ruby/object:Gem::Version
109
- version: '3.8'
110
- - - ">="
111
- - !ruby/object:Gem::Version
112
- version: 3.8.0
113
- - !ruby/object:Gem::Dependency
114
- name: simplecov
115
- requirement: !ruby/object:Gem::Requirement
116
- requirements:
117
- - - "~>"
118
- - !ruby/object:Gem::Version
119
- version: 0.16.0
120
- type: :development
32
+ version: '2.2'
33
+ type: :runtime
121
34
  prerelease: false
122
35
  version_requirements: !ruby/object:Gem::Requirement
123
36
  requirements:
124
37
  - - "~>"
125
38
  - !ruby/object:Gem::Version
126
- version: 0.16.0
39
+ version: '2.2'
127
40
  description: " A library that makes it easy to query the Overpass API and translate
128
41
  its responses into RGeo objects\n"
129
42
  email: janos.rusiczki@gmail.com
@@ -134,20 +47,31 @@ files:
134
47
  - LICENSE
135
48
  - README.md
136
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
137
58
  - lib/underpass/ql/bounding_box.rb
138
- - lib/underpass/ql/parser.rb
139
- - lib/underpass/ql/ql.rb
59
+ - lib/underpass/ql/builder.rb
140
60
  - lib/underpass/ql/query.rb
61
+ - lib/underpass/ql/query_analyzer.rb
141
62
  - lib/underpass/ql/request.rb
142
- - lib/underpass/ql/shape.rb
63
+ - lib/underpass/ql/response.rb
64
+ - lib/underpass/shape.rb
143
65
  - lib/underpass/version.rb
66
+ - lib/underpass/way_chain.rb
144
67
  homepage: http://github.com/haiafara/underpass
145
68
  licenses:
146
69
  - MIT
147
70
  metadata:
148
71
  source_code_uri: http://github.com/haiafara/underpass
149
72
  bug_tracker_uri: http://github.com/haiafara/underpass/issues
150
- post_install_message:
73
+ documentation_uri: https://haiafara.github.io/underpass
74
+ rubygems_mfa_required: 'true'
151
75
  rdoc_options: []
152
76
  require_paths:
153
77
  - lib
@@ -155,16 +79,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
155
79
  requirements:
156
80
  - - ">="
157
81
  - !ruby/object:Gem::Version
158
- version: 2.3.0
82
+ version: 3.4.0
159
83
  required_rubygems_version: !ruby/object:Gem::Requirement
160
84
  requirements:
161
85
  - - ">="
162
86
  - !ruby/object:Gem::Version
163
87
  version: '0'
164
88
  requirements: []
165
- rubyforge_project:
166
- rubygems_version: 2.6.14
167
- signing_key:
89
+ rubygems_version: 3.6.9
168
90
  specification_version: 4
169
91
  summary: A library that translates Overpass API responses into RGeo objects
170
92
  test_files: []
@@ -1,72 +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 << way_matches(way) if way.key?(:tags)
30
- end
31
-
32
- @matches
33
- end
34
-
35
- private
36
-
37
- def way_matches(way)
38
- if open_way?(way)
39
- polygon_from_way(way, @nodes)
40
- else
41
- line_string_from_way(way, @nodes)
42
- end
43
- end
44
-
45
- def open_way?(way)
46
- Underpass::QL::Shape.open_way?(way)
47
- end
48
-
49
- def point_from_node(node)
50
- Underpass::QL::Shape.point_from_node(node)
51
- end
52
-
53
- def polygon_from_way(way, nodes)
54
- Underpass::QL::Shape.polygon_from_way(way, nodes)
55
- end
56
-
57
- def line_string_from_way(way, nodes)
58
- Underpass::QL::Shape.line_string_from_way(way, nodes)
59
- end
60
-
61
- def extract_indexed_nodes(elements)
62
- nodes = elements.select { |e| e[:type] == 'node' }
63
- nodes.map { |e| [e[:id], e] }.to_h
64
- end
65
-
66
- def extract_indexed_ways(elements)
67
- ways = elements.select { |e| e[:type] == 'way' }
68
- ways.map { |e| [e[:id], e] }.to_h
69
- end
70
- end
71
- end
72
- end
@@ -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
@@ -1,40 +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.open_way?(way)
9
- way[:nodes].first == way[:nodes].last
10
- end
11
-
12
- def self.polygon_from_way(way, nodes)
13
- f = RGeo::Geographic.spherical_factory(srid: 4326)
14
- f.polygon(line_string_from_way(way, nodes))
15
- end
16
-
17
- def self.line_string_from_way(way, nodes)
18
- f = RGeo::Geographic.spherical_factory(srid: 4326)
19
- f.line_string(
20
- way[:nodes].map do |n|
21
- f.point(nodes[n][:lon], nodes[n][:lat])
22
- end
23
- )
24
- end
25
-
26
- def self.point_from_node(node)
27
- f = RGeo::Geographic.spherical_factory(srid: 4326)
28
- f.point(node[:lon], node[:lat])
29
- end
30
-
31
- # There should be some sort of 'decorator' to return an object
32
- # with the shape and a copy of the tags as
33
- # Bonus: try to make it RGeo::GeoJSON.encode compatible
34
- # {
35
- # tags: way[:tags],
36
- # shape: shape
37
- # }
38
- end
39
- end
40
- end