turf-ruby 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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