turf-ruby 0.8.1 → 1.0.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/LICENSE.txt +21 -0
- data/README.md +159 -139
- data/lib/turf/along.rb +10 -3
- data/lib/turf/angle.rb +8 -0
- data/lib/turf/area.rb +4 -1
- data/lib/turf/bbox.rb +36 -0
- data/lib/turf/bbox_clip.rb +74 -0
- data/lib/turf/bbox_polygon.rb +41 -0
- data/lib/turf/bearing.rb +5 -2
- data/lib/turf/bezier_spline.rb +8 -0
- data/lib/turf/boolean_clockwise.rb +8 -0
- data/lib/turf/boolean_concave.rb +8 -0
- data/lib/turf/boolean_contains.rb +52 -0
- data/lib/turf/boolean_crosses.rb +8 -0
- data/lib/turf/boolean_disjoint.rb +8 -0
- data/lib/turf/boolean_equal.rb +8 -0
- data/lib/turf/boolean_intersects.rb +8 -0
- data/lib/turf/boolean_overlap.rb +8 -0
- data/lib/turf/boolean_parallel.rb +8 -0
- data/lib/turf/boolean_point_in_polygon.rb +5 -3
- data/lib/turf/boolean_point_on_line.rb +8 -0
- data/lib/turf/boolean_touches.rb +8 -0
- data/lib/turf/boolean_valid.rb +8 -0
- data/lib/turf/boolean_within.rb +8 -0
- data/lib/turf/buffer.rb +8 -0
- data/lib/turf/center.rb +32 -0
- data/lib/turf/center_mean.rb +8 -0
- data/lib/turf/center_median.rb +8 -0
- data/lib/turf/center_of_mass.rb +8 -0
- data/lib/turf/centroid.rb +5 -2
- data/lib/turf/circle.rb +5 -2
- data/lib/turf/clean_coords.rb +8 -0
- data/lib/turf/clone.rb +8 -0
- data/lib/turf/clusters.rb +32 -0
- data/lib/turf/clusters_dbscan.rb +8 -0
- data/lib/turf/clusters_kmeans.rb +8 -0
- data/lib/turf/collect.rb +8 -0
- data/lib/turf/combine.rb +8 -0
- data/lib/turf/concave.rb +8 -0
- data/lib/turf/convex.rb +8 -0
- data/lib/turf/destination.rb +6 -3
- data/lib/turf/difference.rb +8 -0
- data/lib/turf/directional_mean.rb +8 -0
- data/lib/turf/dissolve.rb +8 -0
- data/lib/turf/distance.rb +5 -2
- data/lib/turf/distance_weight.rb +12 -0
- data/lib/turf/ellipse.rb +8 -0
- data/lib/turf/envelope.rb +8 -0
- data/lib/turf/explode.rb +29 -0
- data/lib/turf/flatten.rb +8 -0
- data/lib/turf/flip.rb +8 -0
- data/lib/turf/geojson_rbush.rb +8 -0
- data/lib/turf/great_circle.rb +8 -0
- data/lib/turf/helpers.rb +166 -26
- data/lib/turf/hex_grid.rb +8 -0
- data/lib/turf/interpolate.rb +8 -0
- data/lib/turf/intersect.rb +8 -0
- data/lib/turf/invariant.rb +127 -1
- data/lib/turf/isobands.rb +8 -0
- data/lib/turf/isolines.rb +8 -0
- data/lib/turf/kinks.rb +8 -0
- data/lib/turf/length.rb +6 -3
- data/lib/turf/lib/lineclip.rb +118 -0
- data/lib/turf/line_arc.rb +8 -0
- data/lib/turf/line_chunk.rb +8 -0
- data/lib/turf/line_intersect.rb +8 -0
- data/lib/turf/line_offset.rb +8 -0
- data/lib/turf/line_overlap.rb +8 -0
- data/lib/turf/line_segment.rb +8 -0
- data/lib/turf/line_slice.rb +8 -0
- data/lib/turf/line_slice_along.rb +8 -0
- data/lib/turf/line_split.rb +8 -0
- data/lib/turf/line_to_polygon.rb +8 -0
- data/lib/turf/mask.rb +8 -0
- data/lib/turf/meta.rb +445 -79
- data/lib/turf/midpoint.rb +8 -0
- data/lib/turf/moran_index.rb +8 -0
- data/lib/turf/nearest_neighbor_analysis.rb +8 -0
- data/lib/turf/nearest_point.rb +8 -0
- data/lib/turf/nearest_point_on_line.rb +8 -0
- data/lib/turf/nearest_point_to_line.rb +8 -0
- data/lib/turf/planepoint.rb +8 -0
- data/lib/turf/point_grid.rb +8 -0
- data/lib/turf/point_on_feature.rb +8 -0
- data/lib/turf/point_to_line_distance.rb +8 -0
- data/lib/turf/point_to_polygon_distance.rb +8 -0
- data/lib/turf/points_within_polygon.rb +8 -0
- data/lib/turf/polygon_smooth.rb +8 -0
- data/lib/turf/polygon_tangents.rb +8 -0
- data/lib/turf/polygon_to_line.rb +20 -0
- data/lib/turf/polygonize.rb +8 -0
- data/lib/turf/projection.rb +12 -0
- data/lib/turf/quadrat_analysis.rb +8 -0
- data/lib/turf/random.rb +20 -0
- data/lib/turf/rectangle_grid.rb +8 -0
- data/lib/turf/rewind.rb +8 -0
- data/lib/turf/rhumb_bearing.rb +8 -0
- data/lib/turf/rhumb_destination.rb +8 -0
- data/lib/turf/rhumb_distance.rb +8 -0
- data/lib/turf/sample.rb +8 -0
- data/lib/turf/sector.rb +8 -0
- data/lib/turf/shortest_path.rb +8 -0
- data/lib/turf/simplify.rb +8 -0
- data/lib/turf/square.rb +42 -0
- data/lib/turf/square_grid.rb +8 -0
- data/lib/turf/standard_deviational_ellipse.rb +8 -0
- data/lib/turf/tag.rb +8 -0
- data/lib/turf/tesselate.rb +8 -0
- data/lib/turf/tin.rb +8 -0
- data/lib/turf/transform_rotate.rb +8 -0
- data/lib/turf/transform_scale.rb +8 -0
- data/lib/turf/transform_translate.rb +8 -0
- data/lib/turf/triangle_grid.rb +8 -0
- data/lib/turf/truncate.rb +3 -0
- data/lib/turf/union.rb +8 -0
- data/lib/turf/unkink_polygon.rb +8 -0
- data/lib/turf/version.rb +2 -1
- data/lib/turf/voronoi.rb +8 -0
- data/lib/turf.rb +2 -0
- data/lib/turf_ruby.rb +107 -3
- metadata +105 -2
data/lib/turf/meta.rb
CHANGED
@@ -1,82 +1,160 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "helpers"
|
4
|
+
|
3
5
|
# :nodoc:
|
4
6
|
module Turf
|
5
|
-
#
|
6
|
-
|
7
|
-
#
|
8
|
-
# @
|
9
|
-
# @
|
10
|
-
# @
|
11
|
-
#
|
12
|
-
# @
|
13
|
-
# @yieldparam
|
14
|
-
# @
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
7
|
+
# Iterate over coordinates in any GeoJSON object, similar to Array#each.
|
8
|
+
#
|
9
|
+
# @param geojson [AllGeoJSON] any GeoJSON object
|
10
|
+
# @yield [current_coord, coord_index, feature_index, multi_feature_index, geometry_index]
|
11
|
+
# @yieldparam current_coord [Array<Number>] The current coordinate being processed.
|
12
|
+
# @yieldparam coord_index [Integer] The current index of the coordinate being processed.
|
13
|
+
# @yieldparam feature_index [Integer] The current index of the Feature being processed.
|
14
|
+
# @yieldparam multi_feature_index [Integer] The current index of the Multi-Feature being processed.
|
15
|
+
# @yieldparam geometry_index [Integer] The current index of the Geometry being processed.
|
16
|
+
# @param exclude_wrap_coord [Boolean] whether or not to include the final coordinate
|
17
|
+
# of LinearRings that wraps the ring in its iteration.
|
18
|
+
# @return [void]
|
19
|
+
# @example
|
20
|
+
# features = Turf.feature_collection([
|
21
|
+
# Turf.point([26, 37], {foo: "bar"}),
|
22
|
+
# Turf.point([36, 53], {hello: "world"})
|
23
|
+
# ])
|
24
|
+
#
|
25
|
+
# Turf.coord_each(features, exclude_wrap_coord: false) do |
|
26
|
+
# current_coord,
|
27
|
+
# coord_index,
|
28
|
+
# feature_index,
|
29
|
+
# multi_feature_index,
|
30
|
+
# geometry_index
|
31
|
+
# |
|
32
|
+
# #=current_coord
|
33
|
+
# #=coord_index
|
34
|
+
# #=feature_index
|
35
|
+
# #=multi_feature_index
|
36
|
+
# #=geometry_index
|
37
|
+
# end
|
38
|
+
def coord_each(geojson, exclude_wrap_coord: false)
|
39
|
+
return if geojson.nil?
|
40
|
+
|
41
|
+
coord_index = 0
|
42
|
+
is_geometry_collection = false
|
43
|
+
type = geojson[:type]
|
44
|
+
is_feature_collection = type == "FeatureCollection"
|
45
|
+
is_feature = type == "Feature"
|
46
|
+
stop = is_feature_collection ? geojson[:features].length : 1
|
47
|
+
|
48
|
+
(0...stop).each do |feature_index|
|
49
|
+
geometry_maybe_collection = if is_feature_collection
|
50
|
+
geojson[:features][feature_index][:geometry]
|
51
|
+
elsif is_feature
|
52
|
+
geojson[:geometry]
|
53
|
+
else
|
54
|
+
geojson
|
55
|
+
end
|
56
|
+
|
57
|
+
is_geometry_collection = if geometry_maybe_collection
|
58
|
+
geometry_maybe_collection[:type] == "GeometryCollection"
|
59
|
+
else
|
60
|
+
false
|
61
|
+
end
|
62
|
+
stop_g = is_geometry_collection ? geometry_maybe_collection[:geometries].length : 1
|
63
|
+
|
64
|
+
(0...stop_g).each do |geom_index|
|
65
|
+
multi_feature_index = 0
|
66
|
+
geometry_index = 0
|
67
|
+
geometry = if is_geometry_collection
|
68
|
+
geometry_maybe_collection[:geometries][geom_index]
|
69
|
+
else
|
70
|
+
geometry_maybe_collection
|
71
|
+
end
|
72
|
+
|
73
|
+
next if geometry.nil?
|
74
|
+
|
75
|
+
coords = geometry[:coordinates]
|
76
|
+
geom_type = geometry[:type]
|
77
|
+
wrap_shrink = exclude_wrap_coord && %w[Polygon MultiPolygon].include?(geom_type) ? 1 : 0
|
78
|
+
|
79
|
+
case geom_type
|
80
|
+
when "Point"
|
81
|
+
return false if yield(coords, coord_index, feature_index, multi_feature_index, geometry_index) == false
|
82
|
+
|
83
|
+
coord_index += 1
|
84
|
+
multi_feature_index += 1
|
85
|
+
when "LineString", "MultiPoint"
|
86
|
+
coords.each_with_index do |coord, _j|
|
87
|
+
return false if yield(coord, coord_index, feature_index, multi_feature_index, geometry_index) == false
|
88
|
+
|
89
|
+
coord_index += 1
|
90
|
+
multi_feature_index += 1 if geom_type == "MultiPoint"
|
49
91
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
92
|
+
multi_feature_index += 1 if geom_type == "LineString"
|
93
|
+
when "Polygon", "MultiLineString"
|
94
|
+
coords.each_with_index do |coord, _j|
|
95
|
+
(0...(coord.length - wrap_shrink)).each do |k|
|
96
|
+
return false if yield(coord[k], coord_index, feature_index, multi_feature_index, geometry_index) == false
|
97
|
+
|
98
|
+
coord_index += 1
|
56
99
|
end
|
57
|
-
|
100
|
+
multi_feature_index += 1 if geom_type == "MultiLineString"
|
101
|
+
geometry_index += 1 if geom_type == "Polygon"
|
102
|
+
end
|
103
|
+
multi_feature_index += 1 if geom_type == "Polygon"
|
104
|
+
when "MultiPolygon"
|
105
|
+
coords.each_with_index do |coord, _j|
|
106
|
+
geometry_index = 0
|
107
|
+
coord.each_with_index do |inner_coord, _k|
|
108
|
+
(0...(inner_coord.length - wrap_shrink)).each do |l|
|
109
|
+
if yield(inner_coord[l], coord_index, feature_index, multi_feature_index, geometry_index) == false
|
110
|
+
return false
|
111
|
+
end
|
112
|
+
|
113
|
+
coord_index += 1
|
114
|
+
end
|
58
115
|
geometry_index += 1
|
59
|
-
block.call(coords, geometry_index)
|
60
116
|
end
|
117
|
+
multi_feature_index += 1
|
61
118
|
end
|
119
|
+
when "GeometryCollection"
|
120
|
+
geometry[:geometries].each do |inner_geometry|
|
121
|
+
return false if coord_each(inner_geometry, exclude_wrap_coord: exclude_wrap_coord, &Proc.new) == false
|
122
|
+
end
|
123
|
+
else
|
124
|
+
raise Error, "Unknown Geometry Type"
|
62
125
|
end
|
63
|
-
when "Feature"
|
64
|
-
coord_each(geometry, exclude_wrap_coord: exclude_wrap_coord, &block)
|
65
|
-
else
|
66
|
-
raise Error, "Unknown Geometry Type: #{geometry[:type]}"
|
67
126
|
end
|
68
127
|
end
|
69
|
-
geojson
|
70
128
|
end
|
71
129
|
|
72
|
-
#
|
130
|
+
# Get all coordinates from any GeoJSON object.
|
131
|
+
#
|
132
|
+
# @param geojson [AllGeoJSON] any GeoJSON object
|
133
|
+
# @return [Array<Array<Number>>] coordinate position array
|
134
|
+
# @example
|
135
|
+
# features = Turf.feature_collection([
|
136
|
+
# Turf.point([26, 37], {foo: 'bar'}),
|
137
|
+
# Turf.point([36, 53], {hello: 'world'})
|
138
|
+
# ])
|
139
|
+
#
|
140
|
+
# coords = Turf.coord_all(features)
|
141
|
+
# #= [[26, 37], [36, 53]]
|
142
|
+
def coord_all(geojson)
|
143
|
+
coords = []
|
144
|
+
coord_each(geojson) do |coord|
|
145
|
+
coords.push(coord)
|
146
|
+
end
|
147
|
+
coords
|
148
|
+
end
|
149
|
+
|
150
|
+
# Reduce coordinates in any GeoJSON object, similar to Array.reduce(*args)
|
73
151
|
# @see https://turfjs.org/docs/#coordReduce
|
74
152
|
# @param geojson [FeatureCollection|Geometry|Feature] any GeoJSON object
|
75
153
|
# @param initial_value [*] Value to use as the first argument to the first call of the callback.
|
76
154
|
# @param exclude_wrap_coord [Boolean] whether or not to include the final coordinate of LinearRings that wraps the
|
77
155
|
# ring in its iteration.
|
78
156
|
# @return [*] The value that results from the reduction.
|
79
|
-
def coord_reduce(geojson, initial_value
|
157
|
+
def coord_reduce(geojson, initial_value = nil, exclude_wrap_coord: false)
|
80
158
|
previous_value = initial_value
|
81
159
|
|
82
160
|
coord_each(
|
@@ -98,7 +176,7 @@ module Turf
|
|
98
176
|
previous_value
|
99
177
|
end
|
100
178
|
|
101
|
-
# Iterate over each geometry in any GeoJSON object, similar to Array.forEach()
|
179
|
+
# Iterate over each geometry in any GeoJSON object, similar to Array.forEach(*args)
|
102
180
|
# @see https://turfjs.org/docs/#geomReduce
|
103
181
|
# @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
|
104
182
|
# @yieldparam geom [Geometry] The current Feature being processed.
|
@@ -139,7 +217,7 @@ module Turf
|
|
139
217
|
end
|
140
218
|
end
|
141
219
|
|
142
|
-
# Reduce geometry in any GeoJSON object, similar to Array.reduce().
|
220
|
+
# Reduce geometry in any GeoJSON object, similar to Array.reduce(*args).
|
143
221
|
# @see https://turfjs.org/docs/#geomReduce
|
144
222
|
# @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
|
145
223
|
# @param initial_value [*] Value to use as the first argument to the first call of the callback.
|
@@ -150,7 +228,7 @@ module Turf
|
|
150
228
|
# @yieldparam bbox [Array<number>] Bounding Box Array [west, south, east, north] associated with the Feature
|
151
229
|
# @yieldparam id [string|number] Identifier associated with the Feature
|
152
230
|
# @return [*] The value that results from the reduction.
|
153
|
-
def geom_reduce(geojson, initial_value
|
231
|
+
def geom_reduce(geojson, initial_value = nil)
|
154
232
|
previous_value = initial_value
|
155
233
|
|
156
234
|
geom_each(
|
@@ -206,7 +284,7 @@ module Turf
|
|
206
284
|
features.each_with_index(&block)
|
207
285
|
end
|
208
286
|
|
209
|
-
# Reduce features in any GeoJSON object, similar to Array.reduce().
|
287
|
+
# Reduce features in any GeoJSON object, similar to Array.reduce(*args).
|
210
288
|
# @see https://turfjs.org/docs/#featureReduce
|
211
289
|
# @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
|
212
290
|
# @param initial_value [*] Value to use as the first argument to the first call of the callback.
|
@@ -214,7 +292,7 @@ module Turf
|
|
214
292
|
# @yieldparam feature [Feature<any>] The current Feature being processed.
|
215
293
|
# @yieldparam feature_index [number] The current index of the Feature being processed.
|
216
294
|
# @return [*] The value that results from the reduction.
|
217
|
-
def feature_reduce(geojson, initial_value
|
295
|
+
def feature_reduce(geojson, initial_value = nil)
|
218
296
|
previous_value = initial_value
|
219
297
|
|
220
298
|
feature_each(
|
@@ -245,7 +323,7 @@ module Turf
|
|
245
323
|
geom_each(geojson) do |geometry, feature_index, properties, bbox, id|
|
246
324
|
if geometry.nil?
|
247
325
|
next yield(
|
248
|
-
feature(nil, properties
|
326
|
+
feature(nil, properties, bbox: bbox, id: id),
|
249
327
|
feature_index,
|
250
328
|
0
|
251
329
|
)
|
@@ -254,7 +332,7 @@ module Turf
|
|
254
332
|
case geometry[:type]
|
255
333
|
when "Point", "LineString", "Polygon"
|
256
334
|
yield(
|
257
|
-
feature(geometry, properties
|
335
|
+
feature(geometry, properties, bbox: bbox, id: id),
|
258
336
|
feature_index,
|
259
337
|
0
|
260
338
|
)
|
@@ -266,7 +344,7 @@ module Turf
|
|
266
344
|
coordinates: coordinate
|
267
345
|
}
|
268
346
|
yield(
|
269
|
-
feature(geom, properties
|
347
|
+
feature(geom, properties),
|
270
348
|
feature_index,
|
271
349
|
multi_feature_index
|
272
350
|
)
|
@@ -275,7 +353,7 @@ module Turf
|
|
275
353
|
end
|
276
354
|
end
|
277
355
|
|
278
|
-
# Reduce flattened features in any GeoJSON object, similar to Array.reduce().
|
356
|
+
# Reduce flattened features in any GeoJSON object, similar to Array.reduce(*args).
|
279
357
|
# @see https://turfjs.org/docs/#flattenEach
|
280
358
|
# @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
|
281
359
|
# @param initial_value [*] Value to use as the first argument to the first call of the callback.
|
@@ -284,7 +362,7 @@ module Turf
|
|
284
362
|
# @yieldparam feature_index [number] The current index of the Feature being processed.
|
285
363
|
# @yieldparam multi_feature_index [number] The current index of the Feature in the multi-Feature
|
286
364
|
# @return [*] The value that results from the reduction.
|
287
|
-
def flatten_reduce(geojson, initial_value
|
365
|
+
def flatten_reduce(geojson, initial_value = nil)
|
288
366
|
previous_value = initial_value
|
289
367
|
|
290
368
|
flatten_each(
|
@@ -306,35 +384,43 @@ module Turf
|
|
306
384
|
previous_value
|
307
385
|
end
|
308
386
|
|
309
|
-
# Iterate over 2-vertex line segment in any GeoJSON object, similar to Array.forEach()
|
387
|
+
# Iterate over 2-vertex line segment in any GeoJSON object, similar to Array.forEach(*args)
|
310
388
|
# (Multi)Point geometries do not contain segments therefore they are ignored during this operation.
|
311
389
|
# @see https://turfjs.org/docs/#segmentEach
|
312
390
|
# @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
|
313
391
|
def segment_each(geojson)
|
314
|
-
flatten_each(geojson) do |feature, feature_index|
|
392
|
+
flatten_each(geojson) do |feature, feature_index, multi_feature_index|
|
315
393
|
# Exclude null Geometries
|
316
|
-
|
394
|
+
next if feature[:geometry].nil?
|
317
395
|
|
318
396
|
# (Multi)Point geometries do not contain segments therefore they are ignored during this operation.
|
319
397
|
type = feature[:geometry][:type]
|
320
|
-
|
398
|
+
next if %w[Point MultiPoint].include?(type)
|
321
399
|
|
322
400
|
segment_index = 0
|
323
401
|
|
324
402
|
# Generate 2-vertex line segments
|
325
403
|
previous_coords = nil
|
326
404
|
previous_feature_index = 0
|
327
|
-
|
328
|
-
|
329
|
-
|
405
|
+
previous_multi_index = 0
|
406
|
+
prev_geom_index = 0
|
407
|
+
coord_each(feature) do |current_coord, _coord_index, _feature_index_coord, multi_part_index_coord, geometry_index|
|
408
|
+
# Simulating a meta.coord_reduce(*args) since `reduce` operations cannot be stopped by returning `false`
|
409
|
+
if previous_coords.nil? ||
|
410
|
+
feature_index > previous_feature_index ||
|
411
|
+
multi_part_index_coord > previous_multi_index ||
|
412
|
+
geometry_index > prev_geom_index
|
413
|
+
|
330
414
|
previous_coords = current_coord
|
331
415
|
previous_feature_index = feature_index
|
416
|
+
previous_multi_index = multi_part_index_coord
|
417
|
+
prev_geom_index = geometry_index
|
332
418
|
segment_index = 0
|
333
419
|
next
|
334
420
|
end
|
335
421
|
|
336
|
-
segment = Turf.line_string([previous_coords, current_coord],
|
337
|
-
next unless yield(segment, feature_index)
|
422
|
+
segment = Turf.line_string([previous_coords, current_coord], feature[:properties])
|
423
|
+
next unless yield(segment, feature_index, multi_feature_index, geometry_index, segment_index)
|
338
424
|
|
339
425
|
segment_index += 1
|
340
426
|
previous_coords = current_coord
|
@@ -342,7 +428,7 @@ module Turf
|
|
342
428
|
end
|
343
429
|
end
|
344
430
|
|
345
|
-
def segment_reduce(geojson, initial_value
|
431
|
+
def segment_reduce(geojson, initial_value = nil)
|
346
432
|
previous_value = initial_value
|
347
433
|
started = false
|
348
434
|
|
@@ -365,4 +451,284 @@ module Turf
|
|
365
451
|
|
366
452
|
previous_value
|
367
453
|
end
|
454
|
+
|
455
|
+
# Iterate over properties in any GeoJSON object, similar to Array.forEach.
|
456
|
+
# @see https://turfjs.org/docs/#propEach
|
457
|
+
# @param geojson [FeatureCollection|Feature] any GeoJSON object
|
458
|
+
# @yieldparam current_properties [Hash] The current Properties being processed.
|
459
|
+
# @yieldparam feature_index [number] The current index of the Feature being processed.
|
460
|
+
def prop_each(geojson)
|
461
|
+
case geojson[:type]
|
462
|
+
when "FeatureCollection"
|
463
|
+
geojson[:features].each_with_index do |feature, i|
|
464
|
+
break if yield(feature[:properties], i) == false
|
465
|
+
end
|
466
|
+
when "Feature"
|
467
|
+
yield(geojson[:properties], 0)
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
# Reduce properties in any GeoJSON object into a single value,
|
472
|
+
# similar to how Array.reduce works. However, in this case we lazily run
|
473
|
+
# the reduction, so an array of all properties is unnecessary.
|
474
|
+
# @see https://turfjs.org/docs/#propReduce
|
475
|
+
# @param geojson [FeatureCollection|Feature|Geometry] any GeoJSON object
|
476
|
+
# @param initial_value [Object] Value to use as the first argument to the first call of the callback.
|
477
|
+
# @yieldparam previous_value [Object] The accumulated value previously returned in the last invocation
|
478
|
+
# of the callback, or initial_value, if supplied.
|
479
|
+
# @yieldparam current_properties [Hash] The current Properties being processed.
|
480
|
+
# @yieldparam feature_index [number] The current index of the Feature being processed.
|
481
|
+
# @return [Object] The value that results from the reduction.
|
482
|
+
def prop_reduce(geojson, initial_value = nil)
|
483
|
+
previous_value = initial_value
|
484
|
+
|
485
|
+
prop_each(geojson) do |current_properties, feature_index|
|
486
|
+
previous_value = if feature_index.zero? && initial_value.nil?
|
487
|
+
current_properties
|
488
|
+
else
|
489
|
+
yield(previous_value, current_properties, feature_index)
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
previous_value
|
494
|
+
end
|
495
|
+
|
496
|
+
# Iterate over line or ring coordinates in LineString, Polygon, MultiLineString, MultiPolygon Features or Geometries,
|
497
|
+
# similar to Array.forEach.
|
498
|
+
# @see https://turfjs.org/docs/#lineEach
|
499
|
+
# @param geojson [FeatureCollection<Lines>|Feature<Lines>|Lines|Feature<GeometryCollection>|GeometryCollection]
|
500
|
+
# any GeoJSON object
|
501
|
+
# @yieldparam current_line [Feature<LineString>] The current LineString|LinearRing being processed
|
502
|
+
# @yieldparam feature_index [number] The current index of the Feature being processed
|
503
|
+
# @yieldparam multi_feature_index [number] The current index of the Multi-Feature being processed
|
504
|
+
# @yieldparam geometry_index [number] The current index of the Geometry being processed
|
505
|
+
def line_each(geojson)
|
506
|
+
flatten_each(geojson) do |feature, feature_index, multi_feature_index|
|
507
|
+
next unless feature[:geometry]
|
508
|
+
|
509
|
+
type = feature[:geometry][:type]
|
510
|
+
coords = feature[:geometry][:coordinates]
|
511
|
+
|
512
|
+
case type
|
513
|
+
when "LineString"
|
514
|
+
yield(feature, feature_index, multi_feature_index, 0, 0)
|
515
|
+
when "Polygon"
|
516
|
+
coords.each_with_index do |ring, geometry_index|
|
517
|
+
yield(
|
518
|
+
feature({ type: "LineString", coordinates: ring }, feature[:properties]),
|
519
|
+
feature_index,
|
520
|
+
multi_feature_index,
|
521
|
+
geometry_index
|
522
|
+
)
|
523
|
+
end
|
524
|
+
end
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
# Reduce features in any GeoJSON object, similar to Array.reduce().
|
529
|
+
# @see https://turfjs.org/docs/#lineReduce
|
530
|
+
# @param geojson [FeatureCollection<Lines>|Feature<Lines>|Lines|Feature<GeometryCollection>|GeometryCollection]
|
531
|
+
# any GeoJSON object
|
532
|
+
# @param initial_value [Object] Value to use as the first argument to the first call of the callback.
|
533
|
+
# @yieldparam previous_value [Object] The accumulated value previously returned in the last invocation
|
534
|
+
# of the callback, or initial_value, if supplied.
|
535
|
+
# @yieldparam current_line [Feature<LineString>] The current LineString|LinearRing being processed.
|
536
|
+
# @yieldparam feature_index [number] The current index of the Feature being processed
|
537
|
+
# @yieldparam multi_feature_index [number] The current index of the Multi-Feature being processed
|
538
|
+
# @yieldparam geometry_index [number] The current index of the Geometry being processed
|
539
|
+
# @return [Object] The value that results from the reduction.
|
540
|
+
def line_reduce(geojson, initial_value = nil)
|
541
|
+
previous_value = initial_value
|
542
|
+
|
543
|
+
line_each(geojson) do |current_line, feature_index, multi_feature_index, geometry_index|
|
544
|
+
previous_value = if feature_index.zero? && initial_value.nil?
|
545
|
+
current_line
|
546
|
+
else
|
547
|
+
yield(previous_value, current_line, feature_index, multi_feature_index, geometry_index)
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
previous_value
|
552
|
+
end
|
553
|
+
|
554
|
+
# Finds a particular 2-vertex LineString Segment from a GeoJSON using `@turf/meta` indexes.
|
555
|
+
#
|
556
|
+
# Negative indexes are permitted.
|
557
|
+
# Point & MultiPoint will always return null.
|
558
|
+
#
|
559
|
+
# @param geojson [FeatureCollection|Feature|Geometry] Any GeoJSON Feature or Geometry
|
560
|
+
# @param options [Hash] Optional parameters
|
561
|
+
# @option options [Integer] :feature_index (0) Feature Index
|
562
|
+
# @option options [Integer] :multi_feature_index (0) Multi-Feature Index
|
563
|
+
# @option options [Integer] :geometry_index (0) Geometry Index
|
564
|
+
# @option options [Integer] :segment_index (0) Segment Index
|
565
|
+
# @option options [Hash] :properties ({}) Translate Properties to output LineString
|
566
|
+
# @option options [Array<Number>] :bbox ({}) Translate BBox to output LineString
|
567
|
+
# @option options [String, Integer] :id ({}) Translate Id to output LineString
|
568
|
+
# @return [Feature<LineString>] 2-vertex GeoJSON Feature LineString
|
569
|
+
# @example
|
570
|
+
# multi_line = Turf.multi_line_string([
|
571
|
+
# [[10, 10], [50, 30], [30, 40]],
|
572
|
+
# [[-10, -10], [-50, -30], [-30, -40]]
|
573
|
+
# ])
|
574
|
+
#
|
575
|
+
# # First Segment (defaults are 0)
|
576
|
+
# Turf.find_segment(multi_line)
|
577
|
+
# # => Feature<LineString<[[10, 10], [50, 30]]>>
|
578
|
+
#
|
579
|
+
# # First Segment of 2nd Multi Feature
|
580
|
+
# Turf.find_segment(multi_line, multi_feature_index: 1)
|
581
|
+
# # => Feature<LineString<[[-10, -10], [-50, -30]]>>
|
582
|
+
#
|
583
|
+
# # Last Segment of Last Multi Feature
|
584
|
+
# Turf.find_segment(multi_line, multi_feature_index: -1, segment_index: -1)
|
585
|
+
# # => Feature<LineString<[[-50, -30], [-30, -40]]>>
|
586
|
+
def find_segment(geojson, options = {})
|
587
|
+
options ||= {}
|
588
|
+
raise "options is invalid" unless options.is_a?(Hash)
|
589
|
+
|
590
|
+
feature_index = options.fetch(:feature_index, 0)
|
591
|
+
multi_feature_index = options.fetch(:multi_feature_index, 0)
|
592
|
+
geometry_index = options.fetch(:geometry_index, 0)
|
593
|
+
segment_index = options.fetch(:segment_index, 0)
|
594
|
+
|
595
|
+
properties = options[:properties]
|
596
|
+
geometry = nil
|
597
|
+
|
598
|
+
case geojson[:type]
|
599
|
+
when "FeatureCollection"
|
600
|
+
feature_index += geojson[:features].length if feature_index < 0
|
601
|
+
properties ||= geojson[:features][feature_index][:properties]
|
602
|
+
geometry = geojson[:features][feature_index][:geometry]
|
603
|
+
when "Feature"
|
604
|
+
properties ||= geojson[:properties]
|
605
|
+
geometry = geojson[:geometry]
|
606
|
+
when "Point", "MultiPoint"
|
607
|
+
return nil
|
608
|
+
when "LineString", "Polygon", "MultiLineString", "MultiPolygon"
|
609
|
+
geometry = geojson
|
610
|
+
else
|
611
|
+
raise "geojson is invalid"
|
612
|
+
end
|
613
|
+
|
614
|
+
return nil if geometry.nil?
|
615
|
+
|
616
|
+
coords = geometry[:coordinates]
|
617
|
+
case geometry[:type]
|
618
|
+
when "Point", "MultiPoint"
|
619
|
+
nil
|
620
|
+
when "LineString"
|
621
|
+
segment_index += coords.length - 1 if segment_index < 0
|
622
|
+
line_string([coords[segment_index], coords[segment_index + 1]], properties, options)
|
623
|
+
when "Polygon"
|
624
|
+
geometry_index += coords.length if geometry_index < 0
|
625
|
+
segment_index += coords[geometry_index].length - 1 if segment_index < 0
|
626
|
+
line_string([coords[geometry_index][segment_index], coords[geometry_index][segment_index + 1]], properties,
|
627
|
+
options)
|
628
|
+
when "MultiLineString"
|
629
|
+
multi_feature_index += coords.length if multi_feature_index < 0
|
630
|
+
segment_index += coords[multi_feature_index].length - 1 if segment_index < 0
|
631
|
+
line_string([coords[multi_feature_index][segment_index], coords[multi_feature_index][segment_index + 1]],
|
632
|
+
properties, options)
|
633
|
+
when "MultiPolygon"
|
634
|
+
multi_feature_index += coords.length if multi_feature_index < 0
|
635
|
+
geometry_index += coords[multi_feature_index].length if geometry_index < 0
|
636
|
+
segment_index += coords[multi_feature_index][geometry_index].length - 1 if segment_index < 0
|
637
|
+
line_string(
|
638
|
+
[coords[multi_feature_index][geometry_index][segment_index],
|
639
|
+
coords[multi_feature_index][geometry_index][segment_index + 1],], properties, options
|
640
|
+
)
|
641
|
+
else
|
642
|
+
raise "geojson is invalid"
|
643
|
+
end
|
644
|
+
end
|
645
|
+
|
646
|
+
# Finds a particular Point from a GeoJSON using `@turf/meta` indexes.
|
647
|
+
#
|
648
|
+
# Negative indexes are permitted.
|
649
|
+
#
|
650
|
+
# @param geojson [FeatureCollection|Feature|Geometry] Any GeoJSON Feature or Geometry
|
651
|
+
# @param options [Hash] Optional parameters
|
652
|
+
# @option options [Integer] :feature_index (0) Feature Index
|
653
|
+
# @option options [Integer] :multi_feature_index (0) Multi-Feature Index
|
654
|
+
# @option options [Integer] :geometry_index (0) Geometry Index
|
655
|
+
# @option options [Integer] :coord_index (0) Coord Index
|
656
|
+
# @option options [Hash] :properties ({}) Translate Properties to output Point
|
657
|
+
# @option options [Array<Number>] :bbox ({}) Translate BBox to output Point
|
658
|
+
# @option options [String, Integer] :id ({}) Translate Id to output Point
|
659
|
+
# @return [Feature<Point>] 2-vertex GeoJSON Feature Point
|
660
|
+
# @example
|
661
|
+
# multi_line = Turf.multi_line_string([
|
662
|
+
# [[10, 10], [50, 30], [30, 40]],
|
663
|
+
# [[-10, -10], [-50, -30], [-30, -40]]
|
664
|
+
# ])
|
665
|
+
#
|
666
|
+
# # First Segment (defaults are 0)
|
667
|
+
# Turf.find_point(multi_line)
|
668
|
+
# # => Feature<Point<[10, 10]>>
|
669
|
+
#
|
670
|
+
# # First Segment of the 2nd Multi-Feature
|
671
|
+
# Turf.find_point(multi_line, multi_feature_index: 1)
|
672
|
+
# # => Feature<Point<[-10, -10]>>
|
673
|
+
#
|
674
|
+
# # Last Segment of last Multi-Feature
|
675
|
+
# Turf.find_point(multi_line, multi_feature_index: -1, coord_index: -1)
|
676
|
+
# # => Feature<Point<[-30, -40]>>
|
677
|
+
def find_point(geojson, options = {})
|
678
|
+
options ||= {}
|
679
|
+
raise "options is invalid" unless options.is_a?(Hash)
|
680
|
+
|
681
|
+
feature_index = options[:feature_index] || 0
|
682
|
+
multi_feature_index = options[:multi_feature_index] || 0
|
683
|
+
geometry_index = options[:geometry_index] || 0
|
684
|
+
coord_index = options[:coord_index] || 0
|
685
|
+
|
686
|
+
properties = options[:properties]
|
687
|
+
geometry = nil
|
688
|
+
|
689
|
+
case geojson[:type]
|
690
|
+
when "FeatureCollection"
|
691
|
+
feature_index = geojson[:features].length + feature_index if feature_index < 0
|
692
|
+
properties ||= geojson[:features][feature_index][:properties]
|
693
|
+
geometry = geojson[:features][feature_index][:geometry]
|
694
|
+
when "Feature"
|
695
|
+
properties ||= geojson[:properties]
|
696
|
+
geometry = geojson[:geometry]
|
697
|
+
when "Point", "MultiPoint"
|
698
|
+
return nil
|
699
|
+
when "LineString", "Polygon", "MultiLineString", "MultiPolygon"
|
700
|
+
geometry = geojson
|
701
|
+
else
|
702
|
+
raise "geojson is invalid"
|
703
|
+
end
|
704
|
+
|
705
|
+
return nil if geometry.nil?
|
706
|
+
|
707
|
+
coords = geometry[:coordinates]
|
708
|
+
case geometry[:type]
|
709
|
+
when "Point"
|
710
|
+
point(coords, properties, options)
|
711
|
+
when "MultiPoint"
|
712
|
+
multi_feature_index = coords.length + multi_feature_index if multi_feature_index < 0
|
713
|
+
point(coords[multi_feature_index], properties, options)
|
714
|
+
when "LineString"
|
715
|
+
coord_index = coords.length + coord_index if coord_index < 0
|
716
|
+
point(coords[coord_index], properties, options)
|
717
|
+
when "Polygon"
|
718
|
+
geometry_index = coords.length + geometry_index if geometry_index < 0
|
719
|
+
coord_index = coords[geometry_index].length + coord_index if coord_index < 0
|
720
|
+
point(coords[geometry_index][coord_index], properties, options)
|
721
|
+
when "MultiLineString"
|
722
|
+
multi_feature_index = coords.length + multi_feature_index if multi_feature_index < 0
|
723
|
+
coord_index = coords[multi_feature_index].length + coord_index if coord_index < 0
|
724
|
+
point(coords[multi_feature_index][coord_index], properties, options)
|
725
|
+
when "MultiPolygon"
|
726
|
+
multi_feature_index = coords.length + multi_feature_index if multi_feature_index < 0
|
727
|
+
geometry_index = coords[multi_feature_index].length + geometry_index if geometry_index < 0
|
728
|
+
coord_index = coords[multi_feature_index][geometry_index].length - coord_index if coord_index < 0
|
729
|
+
point(coords[multi_feature_index][geometry_index][coord_index], properties, options)
|
730
|
+
else
|
731
|
+
raise "geojson is invalid"
|
732
|
+
end
|
733
|
+
end
|
368
734
|
end
|