turf-ruby 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a1a13828f696140452584b283d12c6d8c9f365d97cbc0995ccbd275756a84e8
4
- data.tar.gz: 8c9b413efdd827194c98535eb64dfe61bb5057c5aa0c61bc1e3899cf9b79a24c
3
+ metadata.gz: 1449d9f733898e30a4773786b5bf8af4484e90387b2eabea1514673675808bf5
4
+ data.tar.gz: a90f6e2fa677344a1ab82f855dd288dd1ebd7067e8a96bbc36c14c23088aa740
5
5
  SHA512:
6
- metadata.gz: b8ba31f189e103c965d96cf6e424e0e229221e3bf0391a0d45156f841b64d43cdbc690be5fe58555c41bd4d800313d177467b3f00b3fc599f87925f4261d3864
7
- data.tar.gz: e56c866eef2ff30d099e459a4d0d095931de7ce1c72f5d5a91f569600fbb694c3ef410d6ab050ea614dc565a014d36643ab53b9910eeada430c9fc3bbb5da220
6
+ metadata.gz: 57668c76b16fba5796e74b217a2f5e9dcd9b00c5f3898e79ed55ac6b81f9788ec70a74f21639e91129a8930d277c791bae1e62028901079ab17467b2329089c2
7
+ data.tar.gz: 8878e5cc910cf52781b349cc7ac2a3051abed0e46fc7a94bde316185b59930098d0fe2a02014a3cb6b1de0adaf82aade91b7767cd98d098cc57ffe6db91bb81d
data/lib/turf/area.rb ADDED
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ #:nodoc:
4
+ module Turf
5
+ # Takes one or more features and returns their area in square meters.
6
+ # @see https://turfjs.org/docs/#area
7
+ # @param geojson [GeoJSON] input GeoJSON feature(s)
8
+ # @return [number] aria in square meters
9
+ def area(geojson)
10
+ geom_reduce(geojson, initial_value: 0) do |value, geom|
11
+ value + area_calculate_area(geom)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def area_calculate_area(geom)
18
+ case geom[:type]
19
+ when "Polygon"
20
+ area_polygon_area(geom[:coordinates])
21
+ when "MultiPolygon"
22
+ geom[:coordinates].map do |coordinate|
23
+ area_polygon_area(coordinate)
24
+ end.sum
25
+ else
26
+ 0
27
+ end
28
+ end
29
+
30
+ def area_polygon_area(coords)
31
+ outline, *holes = coords
32
+ total = area_ring_area(outline).abs
33
+ holes.each do |hole|
34
+ total -= area_ring_area(hole).abs
35
+ end
36
+ total
37
+ end
38
+
39
+ AREA_RADIUS = 6_378_137
40
+
41
+ def area_ring_area(coords)
42
+ return 0 if coords.size <= 2
43
+
44
+ total = 0
45
+
46
+ coords.each_with_index do |_coord, index|
47
+ lower_index, middle_index, upper_index =
48
+ case index
49
+ when coords.size - 2
50
+ [
51
+ coords.size - 2,
52
+ coords.size - 1,
53
+ 0,
54
+ ]
55
+ when coords.size - 1
56
+ [
57
+ coords.size - 1,
58
+ 0,
59
+ 1,
60
+ ]
61
+ else
62
+ [
63
+ index,
64
+ index + 1,
65
+ index + 2,
66
+ ]
67
+ end
68
+ p1 = coords[lower_index]
69
+ p2 = coords[middle_index]
70
+ p3 = coords[upper_index]
71
+ total += (area_rad(p3[0]) - area_rad(p1[0])) * Math.sin(area_rad(p2[1]))
72
+ end
73
+
74
+ total * AREA_RADIUS * AREA_RADIUS / 2
75
+ end
76
+
77
+ def area_rad(num)
78
+ num * Math::PI / 180
79
+ end
80
+ end
data/lib/turf/helpers.rb CHANGED
@@ -59,12 +59,43 @@ module Turf
59
59
  fc
60
60
  end
61
61
 
62
+ # Creates a Feature based on a coordinate array. Properties can be added optionally.
63
+ # @see https://turfjs.org/docs/#geometryCollection
64
+ # @param geometries [Array<Geometry>] an array of GeoJSON Geometries
65
+ # @param properties [Hash] a Hash of key-value pairs to add as properties
66
+ # @param bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature
67
+ # @param id [string|number] Identifier associated with the Feature
68
+ # @return [Feature<GeometryCollection>] a GeoJSON GeometryCollection Feature
69
+ def geometry_collection(geometries, bbox: nil, id: nil, properties: {})
70
+ geom = {
71
+ type: "GeometryCollection",
72
+ geometries: geometries
73
+ }
74
+
75
+ feature(geom, properties: properties, bbox: bbox, id: id)
76
+ end
77
+
78
+ # Creates a Feature based on a coordinate array. Properties can be added optionally.
79
+ # @param coordinates [Array<Array<number>>] an array of Positions
80
+ # @param properties [Hash] a Hash of key-value pairs to add as properties
81
+ # @param bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature
82
+ # @param id [string|number] Identifier associated with the Feature
83
+ # @return [Feature<MultiPoint>] a MultiPoint feature
84
+ def multi_point(coordinates, properties: {}, bbox: nil, id: nil)
85
+ geom = {
86
+ type: "MultiPoint",
87
+ coordinates: coordinates
88
+ }
89
+
90
+ feature(geom, properties: properties, bbox: bbox, id: id)
91
+ end
92
+
62
93
  # Creates a LineString Feature from an Array of Positions.
63
94
  # @see https://turfjs.org/docs/#lineString
64
95
  # @param coordinates [Array<Array<number>>] an array of Positions
65
96
  # @param properties [Hash] an Hash of key-value pairs to add as properties
66
97
  # @param bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature
67
- # @param id [string | number] Identifier associated with the Feature
98
+ # @param id [string|number] Identifier associated with the Feature
68
99
  # @return [Feature<LineString>] LineString Feature
69
100
  def line_string(coordinates, properties: {}, bbox: nil, id: nil)
70
101
  if coordinates.size < 2
data/lib/turf/meta.rb CHANGED
@@ -13,65 +13,169 @@ module Turf
13
13
  # @yieldparam current_coord [Array<number>] The current coordinate being processed.
14
14
  # @yieldparam coord_index [number] The current index of the coordinate being processed.
15
15
  def coord_each(geojson, exclude_wrap_coord: false, &block)
16
+ coord_all(geojson, exclude_wrap_coord: exclude_wrap_coord).each_with_index(&block)
17
+ end
18
+
19
+ # Get all coordinates from any GeoJSON object.
20
+ # @see https://turfjs.org/docs/#coordAll
21
+ # @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
22
+ # @param exclude_wrap_coord [boolean] whether or not to include the final coordinate of LinearRings that wraps the
23
+ # ring in its iteration
24
+ # @return [Array<Array<number>>] coordinate position array
25
+ def coord_all(geojson, exclude_wrap_coord: false)
26
+ geometries = self.geometries(geojson)
27
+ geometries.flat_map do |geometry|
28
+ next [] if geometry.nil?
29
+
30
+ case geometry[:type]
31
+ when "Point"
32
+ [geometry[:coordinates]]
33
+ when "LineString", "MultiPoint"
34
+ geometry[:coordinates]
35
+ when "Polygon", "MultiLineString"
36
+ geometry[:coordinates].flat_map do |line_coords|
37
+ (
38
+ exclude_wrap_coord ? line_coords.slice(0...-1) : line_coords
39
+ )
40
+ end
41
+ when "MultiPolygon"
42
+ geometry[:coordinates].flat_map do |polygon_coords|
43
+ polygon_coords.flat_map do |line_coords|
44
+ (
45
+ exclude_wrap_coord ? line_coords.slice(0...-1) : line_coords
46
+ )
47
+ end
48
+ end
49
+ when "Feature"
50
+ [].tap do |feature_coords|
51
+ coord_each geometry, exclude_wrap_coord: exclude_wrap_coord do |coord|
52
+ feature_coords.push coord
53
+ end
54
+ end
55
+ else
56
+ raise Error, "Unknown Geometry Type: #{geometry[:type]}"
57
+ end
58
+ end
59
+ end
60
+
61
+ # Reduce coordinates in any GeoJSON object, similar to Array.reduce()
62
+ # @see https://turfjs.org/docs/#coordReduce
63
+ # @param geojson [FeatureCollection|Geometry|Feature] any GeoJSON object
64
+ # @param initial_value [*] Value to use as the first argument to the first call of the callback.
65
+ # @param exclude_wrap_coord [Boolean] whether or not to include the final coordinate of LinearRings that wraps the
66
+ # ring in its iteration.
67
+ # @return [*] The value that results from the reduction.
68
+ def coord_reduce(geojson, initial_value: nil, exclude_wrap_coord: false)
69
+ previous_value = initial_value
70
+
71
+ coord_each(
72
+ geojson,
73
+ exclude_wrap_coord: exclude_wrap_coord,
74
+ ) do |current_coord, coord_index|
75
+ previous_value =
76
+ if coord_index.zero? && initial_value.nil?
77
+ current_coord
78
+ else
79
+ yield(
80
+ previous_value,
81
+ current_coord,
82
+ coord_index
83
+ )
84
+ end
85
+ end
86
+
87
+ previous_value
88
+ end
89
+
90
+ # Iterate over each geometry in any GeoJSON object, similar to Array.forEach()
91
+ # @see https://turfjs.org/docs/#geomReduce
92
+ # @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
93
+ # @yieldparam geom [Geometry] The current Feature being processed.
94
+ # @yieldparam feature_index [number] The current index of the Feature being processed.
95
+ # @yieldparam properties [Hash] an Object of key-value pairs to add as properties
96
+ # @yieldparam bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature
97
+ # @yieldparam id [string|number] Identifier associated with the Feature
98
+ def geom_each(geojson)
16
99
  return unless geojson
17
100
 
18
101
  geojson = deep_symbolize_keys geojson
19
- geometries = []
102
+
103
+ # [geometry, properties, bbox, id]
104
+ entries = []
105
+
20
106
  case geojson[:type]
21
107
  when "FeatureCollection"
22
108
  geojson[:features].each do |feature|
23
- geometries.push feature[:geometry]
109
+ entries.push [feature[:geometry], feature[:properties], feature[:bbox], feature[:id]]
24
110
  end
25
111
  when "Feature"
26
- geometries.push geojson[:geometry]
112
+ entries.push [geojson[:geometry], geojson[:properties], geojson[:bbox], geojson[:id]]
27
113
  else
28
- geometries.push geojson
114
+ entries.push [geojson, {}, nil, nil]
29
115
  end
30
116
 
31
117
  # flatten GeometryCollection
32
- geometries =
33
- geometries.map do |geometry|
34
- next if geometry.nil?
35
- next geometry unless geometry[:type] == "GeometryCollection"
36
-
37
- geometry[:geometries]
38
- end.flatten
39
-
40
- coords =
41
- geometries.flat_map do |geometry|
42
- next nil if geometry.nil?
43
-
44
- case geometry[:type]
45
- when "Point"
46
- [geometry[:coordinates]]
47
- when "LineString", "MultiPoint"
48
- geometry[:coordinates]
49
- when "Polygon", "MultiLineString"
50
- geometry[:coordinates].flat_map do |line_coords|
51
- (
52
- exclude_wrap_coord ? line_coords.slice(0...-1) : line_coords
53
- )
54
- end
55
- when "MultiPolygon"
56
- geometry[:coordinates].flat_map do |polygon_coords|
57
- polygon_coords.flat_map do |line_coords|
58
- (
59
- exclude_wrap_coord ? line_coords.slice(0...-1) : line_coords
60
- )
61
- end
62
- end
63
- when "Feature"
64
- [].tap do |feature_coords|
65
- coord_each geometry, exclude_wrap_coord: exclude_wrap_coord do |coord|
66
- feature_coords.push coord
67
- end
68
- end
118
+ entries =
119
+ entries.flat_map do |entry|
120
+ geometry, properties, bbox, id = entry
121
+ next [entry] if geometry.nil?
122
+ next [entry] unless geometry[:type] == "GeometryCollection"
123
+
124
+ geometry[:geometries].map do |sub_geometry|
125
+ [sub_geometry, properties, bbox, id]
126
+ end
127
+ end
128
+
129
+ entries.each_with_index do |entry, entry_index|
130
+ geometry, properties, bbox, id = entry
131
+ yield geometry, entry_index, properties, bbox, id
132
+ end
133
+ end
134
+
135
+ # Reduce geometry in any GeoJSON object, similar to Array.reduce().
136
+ # @see https://turfjs.org/docs/#geomReduce
137
+ # @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
138
+ # @param initial_value [*] Value to use as the first argument to the first call of the callback.
139
+ # @yieldparam previous_value [*] Result of previous reduction
140
+ # @yieldparam geom [Geometry] The current Feature being processed.
141
+ # @yieldparam geom_index [number] The current index of the Feature being processed.
142
+ # @yieldparam properties [Hash] an Object of key-value pairs to add as properties
143
+ # @yieldparam bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature
144
+ # @yieldparam id [string|number] Identifier associated with the Feature
145
+ # @return [*] The value that results from the reduction.
146
+ def geom_reduce(geojson, initial_value: nil)
147
+ previous_value = initial_value
148
+
149
+ geom_each(
150
+ geojson,
151
+ ) do |geom, geom_index, properties, bbox, id|
152
+ previous_value =
153
+ if geom_index.zero? && initial_value.nil?
154
+ geom
69
155
  else
70
- raise Error, "Unknown Geometry Type: #{geometry[:type]}"
156
+ yield(
157
+ previous_value,
158
+ geom,
159
+ geom_index,
160
+ properties,
161
+ bbox,
162
+ id
163
+ )
71
164
  end
72
- end.compact
165
+ end
166
+
167
+ previous_value
168
+ end
73
169
 
74
- coords.each_with_index(&block)
170
+ # Get all Geometry
171
+ # @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
172
+ # @return [Array<Geometry>] list of Geometry
173
+ def geometries(geojson)
174
+ [].tap do |geometries|
175
+ geom_each(geojson) do |geometry|
176
+ geometries.push(geometry)
177
+ end
178
+ end
75
179
  end
76
180
 
77
181
  # Iterate over features in any GeoJSON object, similar to Array.forEach.
@@ -83,12 +187,115 @@ module Turf
83
187
  def feature_each(geojson, &block)
84
188
  return unless geojson
85
189
 
190
+ features = []
86
191
  geojson = deep_symbolize_keys geojson
87
192
  case geojson[:type]
88
193
  when "Feature"
89
- yield geojson, 0
194
+ features.push geojson
90
195
  when "FeatureCollection"
91
- geojson[:features].each_with_index(&block)
196
+ features.push(*geojson[:features])
197
+ end
198
+
199
+ features.each_with_index(&block)
200
+ end
201
+
202
+ # Reduce features in any GeoJSON object, similar to Array.reduce().
203
+ # @see https://turfjs.org/docs/#featureReduce
204
+ # @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
205
+ # @param initial_value [*] Value to use as the first argument to the first call of the callback.
206
+ # @yieldparam previous_value [*] Result of previous reduction
207
+ # @yieldparam feature [Feature<any>] The current Feature being processed.
208
+ # @yieldparam feature_index [number] The current index of the Feature being processed.
209
+ # @return [*] The value that results from the reduction.
210
+ def feature_reduce(geojson, initial_value: nil)
211
+ previous_value = initial_value
212
+
213
+ feature_each(
214
+ geojson,
215
+ ) do |feature, feature_index|
216
+ previous_value =
217
+ if feature_index.zero? && initial_value.nil?
218
+ feature
219
+ else
220
+ yield(
221
+ previous_value,
222
+ feature,
223
+ feature_index
224
+ )
225
+ end
92
226
  end
227
+
228
+ previous_value
229
+ end
230
+
231
+ # Iterate over flattened features in any GeoJSON object, similar to Array.forEach.
232
+ # @see https://turfjs.org/docs/#flattenEach
233
+ # @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
234
+ # @yieldparam feature [Feature<any>] The current Feature being processed.
235
+ # @yieldparam feature_index [number] The current index of the Feature being processed.
236
+ # @yieldparam multi_feature_index [number] The current index of the Feature in the multi-Feature
237
+ def flatten_each(geojson)
238
+ geom_each(geojson) do |geometry, feature_index, properties, bbox, id|
239
+ if geometry.nil?
240
+ next yield(
241
+ feature(nil, properties: properties, bbox: bbox, id: id),
242
+ feature_index,
243
+ 0
244
+ )
245
+ end
246
+
247
+ case geometry[:type]
248
+ when "Point", "LineString", "Polygon"
249
+ yield(
250
+ feature(geometry, properties: properties, bbox: bbox, id: id),
251
+ feature_index,
252
+ 0
253
+ )
254
+ when "MultiPoint", "MultiLineString", "MultiPolygon"
255
+ geom_type = geometry[:type].sub(/^Multi/, "")
256
+ geometry[:coordinates].each_with_index do |coordinate, multi_feature_index|
257
+ geom = {
258
+ type: geom_type,
259
+ coordinates: coordinate
260
+ }
261
+ yield(
262
+ feature(geom, properties: properties),
263
+ feature_index,
264
+ multi_feature_index
265
+ )
266
+ end
267
+ end
268
+ end
269
+ end
270
+
271
+ # Reduce flattened features in any GeoJSON object, similar to Array.reduce().
272
+ # @see https://turfjs.org/docs/#flattenEach
273
+ # @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
274
+ # @param initial_value [*] Value to use as the first argument to the first call of the callback.
275
+ # @yieldparam previous_value [*] Result of previous reduction
276
+ # @yieldparam feature [Feature<any>] The current Feature being processed.
277
+ # @yieldparam feature_index [number] The current index of the Feature being processed.
278
+ # @yieldparam multi_feature_index [number] The current index of the Feature in the multi-Feature
279
+ # @return [*] The value that results from the reduction.
280
+ def flatten_reduce(geojson, initial_value: nil)
281
+ previous_value = initial_value
282
+
283
+ flatten_each(
284
+ geojson,
285
+ ) do |feature, feature_index, multi_feature_index|
286
+ previous_value =
287
+ if feature_index.zero? && multi_feature_index.zero? && initial_value.nil?
288
+ feature
289
+ else
290
+ yield(
291
+ previous_value,
292
+ feature,
293
+ feature_index,
294
+ multi_feature_index
295
+ )
296
+ end
297
+ end
298
+
299
+ previous_value
93
300
  end
94
301
  end
data/lib/turf/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Turf
4
4
  # Version of turf-ruby
5
- VERSION = "0.5.0"
5
+ VERSION = "0.6.0"
6
6
  end
data/lib/turf_ruby.rb CHANGED
@@ -13,5 +13,6 @@ require "turf/invariant"
13
13
  require "turf/boolean_point_in_polygon"
14
14
  require "turf/centroid"
15
15
  require "turf/meta"
16
+ require "turf/area"
16
17
 
17
18
  require "turf"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turf-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rafael Santos
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-06-23 00:00:00.000000000 Z
11
+ date: 2021-07-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Turf Ruby is a Ruby library for spatial analysis. It includes traditional
14
14
  spatial operations, helper functions for creating GeoJSON data, and data classification
@@ -21,6 +21,7 @@ extra_rdoc_files: []
21
21
  files:
22
22
  - lib/turf.rb
23
23
  - lib/turf/along.rb
24
+ - lib/turf/area.rb
24
25
  - lib/turf/bearing.rb
25
26
  - lib/turf/boolean_point_in_polygon.rb
26
27
  - lib/turf/centroid.rb