h3 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +19 -0
- data/.gitignore +3 -0
- data/.rspec +1 -0
- data/.rubocop.yml +255 -0
- data/.travis.yml +19 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +42 -0
- data/LICENSE.md +21 -0
- data/README.md +51 -0
- data/Rakefile +3 -0
- data/h3.gemspec +21 -0
- data/lib/h3.rb +36 -0
- data/lib/h3/bindings.rb +12 -0
- data/lib/h3/bindings/base.rb +15 -0
- data/lib/h3/bindings/private.rb +32 -0
- data/lib/h3/bindings/structs.rb +59 -0
- data/lib/h3/geo_json.rb +169 -0
- data/lib/h3/hierarchy.rb +160 -0
- data/lib/h3/indexing.rb +80 -0
- data/lib/h3/inspection.rb +105 -0
- data/lib/h3/miscellaneous.rb +99 -0
- data/lib/h3/regions.rb +239 -0
- data/lib/h3/traversal.rb +287 -0
- data/lib/h3/unidirectional_edges.rb +146 -0
- data/lib/h3/version.rb +3 -0
- data/spec/geo_json_spec.rb +118 -0
- data/spec/hierarchy_spec.rb +159 -0
- data/spec/indexing_spec.rb +92 -0
- data/spec/inspection_spec.rb +90 -0
- data/spec/miscellaneous_spec.rb +75 -0
- data/spec/region_spec.rb +71 -0
- data/spec/spec_helper.rb +100 -0
- data/spec/support/fixtures/australia.json +1 -0
- data/spec/support/fixtures/banbury.json +1 -0
- data/spec/support/fixtures/banbury_feature.json +93 -0
- data/spec/support/fixtures/banbury_feature_collection.json +98 -0
- data/spec/support/fixtures/banbury_out.json +1 -0
- data/spec/support/fixtures/banbury_without_holes.json +1 -0
- data/spec/support/shared_contexts/constants.rb +4 -0
- data/spec/traversal_spec.rb +343 -0
- data/spec/unidirectional_edges_spec.rb +119 -0
- metadata +155 -0
data/lib/h3.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require "ffi"
|
2
|
+
require "rgeo/geo_json"
|
3
|
+
|
4
|
+
require "h3/bindings"
|
5
|
+
require "h3/geo_json"
|
6
|
+
require "h3/hierarchy"
|
7
|
+
require "h3/indexing"
|
8
|
+
require "h3/inspection"
|
9
|
+
require "h3/miscellaneous"
|
10
|
+
require "h3/regions"
|
11
|
+
require "h3/traversal"
|
12
|
+
require "h3/unidirectional_edges"
|
13
|
+
|
14
|
+
# The main H3 namespace.
|
15
|
+
#
|
16
|
+
# All public methods for the library are defined here.
|
17
|
+
#
|
18
|
+
# @see https://uber.github.io/h3/#/documentation/overview/introduction
|
19
|
+
module H3
|
20
|
+
class << self
|
21
|
+
include GeoJSON
|
22
|
+
include Hierarchy
|
23
|
+
include Miscellaneous
|
24
|
+
include Indexing
|
25
|
+
include Inspection
|
26
|
+
include Regions
|
27
|
+
include Traversal
|
28
|
+
include UnidirectionalEdges
|
29
|
+
end
|
30
|
+
|
31
|
+
PREDICATES = %i(h3_indexes_neighbors h3_pentagon h3_res_class_3
|
32
|
+
h3_unidirectional_edge_valid h3_valid).freeze
|
33
|
+
PREDICATES.each do |predicate|
|
34
|
+
singleton_class.send(:alias_method, "#{predicate}?".to_sym, predicate)
|
35
|
+
end
|
36
|
+
end
|
data/lib/h3/bindings.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "h3/bindings/base"
|
2
|
+
require "h3/bindings/structs"
|
3
|
+
require "h3/bindings/private"
|
4
|
+
|
5
|
+
module H3
|
6
|
+
# Internal bindings related modules and classes.
|
7
|
+
#
|
8
|
+
# These are intended to be used by the library's public methods
|
9
|
+
# and not to be used directly by client code.
|
10
|
+
module Bindings
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module H3
|
2
|
+
module Bindings
|
3
|
+
# Base for FFI Bindings.
|
4
|
+
#
|
5
|
+
# When extended, this module sets up FFI to use the H3 C library.
|
6
|
+
module Base
|
7
|
+
def self.extended(base)
|
8
|
+
base.extend FFI::Library
|
9
|
+
base.ffi_lib ["libh3", "libh3.1"]
|
10
|
+
base.typedef :ulong_long, :h3_index
|
11
|
+
base.const_set('H3_INDEX', :ulong_long)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module H3
|
2
|
+
module Bindings
|
3
|
+
# Private H3 functions which should not be called directly.
|
4
|
+
#
|
5
|
+
# This module provides bindings that do not have to be invoked directly by clients
|
6
|
+
# of the library. They are used only internally to provide related public interface.
|
7
|
+
module Private
|
8
|
+
extend H3::Bindings::Base
|
9
|
+
|
10
|
+
attach_function :compact, [:pointer, :pointer, :int], :bool
|
11
|
+
attach_function :geo_to_h3, :geoToH3, [ Bindings::Structs::GeoCoord.by_ref, :int ], :h3_index
|
12
|
+
attach_function :h3_indexes_from_unidirectional_edge, :getH3IndexesFromUnidirectionalEdge, [ :h3_index, :pointer ], :void
|
13
|
+
attach_function :h3_unidirectional_edges_from_hexagon, :getH3UnidirectionalEdgesFromHexagon, [ :h3_index, :pointer ], :void
|
14
|
+
attach_function :h3_set_to_linked_geo, :h3SetToLinkedGeo, [ :pointer, :int, Bindings::Structs::LinkedGeoPolygon.by_ref ], :void
|
15
|
+
attach_function :h3_to_children, :h3ToChildren, [ :h3_index, :int, :pointer ], :void
|
16
|
+
attach_function :h3_to_geo, :h3ToGeo, [ :h3_index, Bindings::Structs::GeoCoord.by_ref ], :void
|
17
|
+
attach_function :h3_to_string, :h3ToString, [ :h3_index, :pointer, :int], :void
|
18
|
+
attach_function :h3_to_geo_boundary, :h3ToGeoBoundary, [:h3_index, Bindings::Structs::GeoBoundary.by_ref ], :void
|
19
|
+
attach_function :h3_unidirectional_edge_boundary, :getH3UnidirectionalEdgeBoundary, [:h3_index, :pointer], :void
|
20
|
+
attach_function :hex_range, :hexRange, [ :h3_index, :int, :pointer ], :bool
|
21
|
+
attach_function :hex_range_distances, :hexRangeDistances, [:h3_index, :int, :pointer, :pointer], :bool
|
22
|
+
attach_function :hex_ranges, :hexRanges, [ :pointer, :int, :int, :pointer ], :bool
|
23
|
+
attach_function :hex_ring, :hexRing, [:h3_index, :int, :pointer], :bool
|
24
|
+
attach_function :k_ring, :kRing, [:h3_index, :int, :pointer], :void
|
25
|
+
attach_function :k_ring_distances, :kRingDistances, [:h3_index, :int, :pointer, :pointer], :bool
|
26
|
+
attach_function :max_polyfill_size, :maxPolyfillSize, [Bindings::Structs::GeoPolygon.by_ref, :int], :int
|
27
|
+
attach_function :max_uncompact_size, :maxUncompactSize, [:pointer, :int, :int], :int
|
28
|
+
attach_function :polyfill, [ :pointer, :int, :pointer ], :void
|
29
|
+
attach_function :uncompact, [:pointer, :int, :pointer, :int, :int], :bool
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module H3
|
2
|
+
module Bindings
|
3
|
+
# FFI Structs.
|
4
|
+
#
|
5
|
+
# These match the structs defined in H3's header file and are required
|
6
|
+
# to correctly interact with the library's functions.
|
7
|
+
module Structs
|
8
|
+
extend FFI::Library
|
9
|
+
|
10
|
+
class GeoCoord < FFI::Struct
|
11
|
+
layout :lat, :double,
|
12
|
+
:lon, :double
|
13
|
+
end
|
14
|
+
|
15
|
+
class GeoBoundary < FFI::Struct
|
16
|
+
layout :num_verts, :int,
|
17
|
+
:verts, [:double, 20] # array of GeoCoord structs (must be fixed length)
|
18
|
+
end
|
19
|
+
|
20
|
+
class GeoFence < FFI::Struct
|
21
|
+
layout :num_verts, :int,
|
22
|
+
:verts, :pointer # array of GeoCoord structs
|
23
|
+
end
|
24
|
+
|
25
|
+
class GeoPolygon < FFI::Struct
|
26
|
+
layout :geofence, GeoFence,
|
27
|
+
:num_holes, :int,
|
28
|
+
:holes, :pointer # array of GeoFence structs
|
29
|
+
end
|
30
|
+
|
31
|
+
class GeoMultiPolygon < FFI::Struct
|
32
|
+
layout :num_polygons, :int,
|
33
|
+
:polygons, :pointer # array of GeoPolygon structs
|
34
|
+
end
|
35
|
+
|
36
|
+
class LinkedGeoCoord < FFI::Struct
|
37
|
+
layout :vertex, GeoCoord,
|
38
|
+
:next, LinkedGeoCoord.ptr
|
39
|
+
end
|
40
|
+
|
41
|
+
class LinkedGeoLoop < FFI::Struct
|
42
|
+
layout :first, LinkedGeoCoord.ptr,
|
43
|
+
:last, LinkedGeoCoord.ptr,
|
44
|
+
:next, LinkedGeoLoop.ptr
|
45
|
+
end
|
46
|
+
|
47
|
+
class LinkedGeoPolygon < FFI::Struct
|
48
|
+
layout :first, LinkedGeoLoop.ptr,
|
49
|
+
:last, LinkedGeoLoop.ptr,
|
50
|
+
:next, LinkedGeoPolygon.ptr
|
51
|
+
end
|
52
|
+
|
53
|
+
class CoordIJ < FFI::Struct
|
54
|
+
layout :i, :int,
|
55
|
+
:j, :int
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/h3/geo_json.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
module H3
|
2
|
+
# GeoJSON helper methods.
|
3
|
+
#
|
4
|
+
# This module allows conversions between GeoJSON polygon data and a nested set of coordinates.
|
5
|
+
#
|
6
|
+
# It should be noted that H3 describes coordinates as number pairs in the form
|
7
|
+
#
|
8
|
+
# [latitude, longitude]
|
9
|
+
#
|
10
|
+
# whereas the GeoJSON standard uses
|
11
|
+
#
|
12
|
+
# [longitude, latitude]
|
13
|
+
#
|
14
|
+
# Both use degrees.
|
15
|
+
#
|
16
|
+
# == Coordinates Array
|
17
|
+
#
|
18
|
+
# We use a nested array to hold coordinates describing a geographical region.
|
19
|
+
#
|
20
|
+
# The first element in the array is an external geofence boundary, composed of an array of
|
21
|
+
# coordinates as 2-element arrays of the form [latitude, longitude].
|
22
|
+
#
|
23
|
+
# Any further elements in the array are further geofence arrays of coordinates which describe
|
24
|
+
# holes that may be present in the polygon.
|
25
|
+
#
|
26
|
+
# Specific examples are shown in the individual method details.
|
27
|
+
#
|
28
|
+
# @see http://geojson.io geojson.io - A graphical tool to see GeoJSON data rendered on a world map.
|
29
|
+
# @see https://tools.ietf.org/html/rfc7946 The GeoJSON RFC standard.
|
30
|
+
module GeoJSON
|
31
|
+
# Convert a GeoJSON document to a nested array of coordinates.
|
32
|
+
#
|
33
|
+
# @param [String] input The GeoJSON document. This can be a feature collection, feature,
|
34
|
+
# or polygon. If a feature collection is provided, the first feature is used.
|
35
|
+
#
|
36
|
+
# @example Convert a GeoJSON document of Banbury to a set of nested coordinates.
|
37
|
+
# document = "{\"type\":\"Polygon\",\"coordinates\":[
|
38
|
+
# [
|
39
|
+
# [-1.7358398437499998,52.24630137198303], [-1.8923950195312498,52.05249047600099],
|
40
|
+
# [-1.56829833984375,51.891749018068246], [-1.27716064453125,51.91208502557545],
|
41
|
+
# [-1.19476318359375,52.032218104145294], [-1.24420166015625,52.19413974159753],
|
42
|
+
# [-1.5902709960937498,52.24125614966341], [-1.7358398437499998,52.24630137198303]
|
43
|
+
# ],
|
44
|
+
# [
|
45
|
+
# [-1.58203125,52.12590076522272], [-1.476287841796875,52.12590076522272],
|
46
|
+
# [-1.46392822265625,52.075285904832334], [-1.58203125,52.06937709602395],
|
47
|
+
# [-1.58203125,52.12590076522272]
|
48
|
+
# ],
|
49
|
+
# [
|
50
|
+
# [-1.4556884765625,52.01531743663362], [-1.483154296875,51.97642166216334],
|
51
|
+
# [-1.3677978515625,51.96626938051444], [-1.3568115234375,52.0102459910103],
|
52
|
+
# [-1.4556884765625,52.01531743663362]
|
53
|
+
# ]
|
54
|
+
# ]}"
|
55
|
+
# H3.geo_json_to_coordinates(document)
|
56
|
+
# [
|
57
|
+
# [
|
58
|
+
# [52.24630137198303, -1.7358398437499998], [52.05249047600099, -1.8923950195312498],
|
59
|
+
# [51.891749018068246, -1.56829833984375], [51.91208502557545, -1.27716064453125],
|
60
|
+
# [52.032218104145294, -1.19476318359375], [52.19413974159753, -1.24420166015625],
|
61
|
+
# [52.24125614966341, -1.5902709960937498], [52.24630137198303, -1.7358398437499998]
|
62
|
+
# ],
|
63
|
+
# [
|
64
|
+
# [52.12590076522272, -1.58203125], [52.12590076522272, -1.476287841796875],
|
65
|
+
# [52.075285904832334, -1.46392822265625], [52.06937709602395, -1.58203125],
|
66
|
+
# [52.12590076522272, -1.58203125]
|
67
|
+
# ],
|
68
|
+
# [
|
69
|
+
# [52.01531743663362, -1.4556884765625], [51.97642166216334, -1.483154296875],
|
70
|
+
# [51.96626938051444, -1.3677978515625], [52.0102459910103, -1.3568115234375],
|
71
|
+
# [52.01531743663362, -1.4556884765625]
|
72
|
+
# ]
|
73
|
+
# ]
|
74
|
+
#
|
75
|
+
# @raise [ArgumentError] Failed to parse the GeoJSON document.
|
76
|
+
#
|
77
|
+
# @return [Array<Array<Array>>] Nested array of coordinates.
|
78
|
+
def geo_json_to_coordinates(input)
|
79
|
+
geom = RGeo::GeoJSON.decode(input)
|
80
|
+
coordinates = if geom.respond_to?(:first) # feature collection
|
81
|
+
geom.first.geometry.coordinates
|
82
|
+
elsif geom.respond_to?(:geometry) # feature
|
83
|
+
geom.geometry.coordinates
|
84
|
+
elsif geom.respond_to?(:coordinates) # polygon
|
85
|
+
geom.coordinates
|
86
|
+
else
|
87
|
+
failed_to_parse!
|
88
|
+
end
|
89
|
+
swap_lat_lon(coordinates) || failed_to_parse!
|
90
|
+
rescue JSON::ParserError
|
91
|
+
failed_to_parse!
|
92
|
+
end
|
93
|
+
|
94
|
+
# Convert a nested array of coordinates to a GeoJSON document
|
95
|
+
#
|
96
|
+
# @param [Array<Array<Array>>] coordinates Nested array of coordinates.
|
97
|
+
#
|
98
|
+
# @example Convert a set of nested coordinates of Banbury to a GeoJSON document.
|
99
|
+
# coordinates = [
|
100
|
+
# [
|
101
|
+
# [52.24630137198303, -1.7358398437499998], [52.05249047600099, -1.8923950195312498],
|
102
|
+
# [51.891749018068246, -1.56829833984375], [51.91208502557545, -1.27716064453125],
|
103
|
+
# [52.032218104145294, -1.19476318359375], [52.19413974159753, -1.24420166015625],
|
104
|
+
# [52.24125614966341, -1.5902709960937498], [52.24630137198303, -1.7358398437499998]
|
105
|
+
# ],
|
106
|
+
# [
|
107
|
+
# [52.12590076522272, -1.58203125], [52.12590076522272, -1.476287841796875],
|
108
|
+
# [52.075285904832334, -1.46392822265625], [52.06937709602395, -1.58203125],
|
109
|
+
# [52.12590076522272, -1.58203125]
|
110
|
+
# ],
|
111
|
+
# [
|
112
|
+
# [52.01531743663362, -1.4556884765625], [51.97642166216334, -1.483154296875],
|
113
|
+
# [51.96626938051444, -1.3677978515625], [52.0102459910103, -1.3568115234375],
|
114
|
+
# [52.01531743663362, -1.4556884765625]
|
115
|
+
# ]
|
116
|
+
# ]
|
117
|
+
# H3.coordinates_to_geo_json(coordinates)
|
118
|
+
# "{\"type\":\"Polygon\",\"coordinates\":[
|
119
|
+
# [
|
120
|
+
# [-1.7358398437499998,52.24630137198303], [-1.8923950195312498,52.05249047600099],
|
121
|
+
# [-1.56829833984375,51.891749018068246], [-1.27716064453125,51.91208502557545],
|
122
|
+
# [-1.19476318359375,52.032218104145294], [-1.24420166015625,52.19413974159753],
|
123
|
+
# [-1.5902709960937498,52.24125614966341], [-1.7358398437499998,52.24630137198303]
|
124
|
+
# ],
|
125
|
+
# [
|
126
|
+
# [-1.58203125,52.12590076522272], [-1.476287841796875,52.12590076522272],
|
127
|
+
# [-1.46392822265625,52.075285904832334], [-1.58203125,52.06937709602395],
|
128
|
+
# [-1.58203125,52.12590076522272]
|
129
|
+
# ],
|
130
|
+
# [
|
131
|
+
# [-1.4556884765625,52.01531743663362], [-1.483154296875,51.97642166216334],
|
132
|
+
# [-1.3677978515625,51.96626938051444], [-1.3568115234375,52.0102459910103],
|
133
|
+
# [-1.4556884765625,52.01531743663362]
|
134
|
+
# ]
|
135
|
+
# ]}"
|
136
|
+
#
|
137
|
+
# @raise [ArgumentError] Failed to parse the given coordinates.
|
138
|
+
#
|
139
|
+
# @return [String] GeoJSON document.
|
140
|
+
def coordinates_to_geo_json(coordinates)
|
141
|
+
coordinates = swap_lat_lon(coordinates)
|
142
|
+
outer_coords, *inner_coords = coordinates
|
143
|
+
factory = RGeo::Cartesian.simple_factory
|
144
|
+
exterior = factory.linear_ring(outer_coords.map { |lon, lat| factory.point(lon, lat) })
|
145
|
+
interior_rings = inner_coords.map do |polygon|
|
146
|
+
factory.linear_ring(polygon.map { |lon, lat| factory.point(lon, lat) })
|
147
|
+
end
|
148
|
+
polygon = factory.polygon(exterior, interior_rings)
|
149
|
+
RGeo::GeoJSON.encode(polygon).to_json
|
150
|
+
rescue RGeo::Error::InvalidGeometry, NoMethodError
|
151
|
+
invalid_coordinates!
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
# geo-json coordinates use [lon, lat], h3 uses [lat, lon]
|
157
|
+
def swap_lat_lon(coordinates)
|
158
|
+
coordinates.map { |polygon| polygon.map { |x, y| [y, x] } }
|
159
|
+
end
|
160
|
+
|
161
|
+
def failed_to_parse!
|
162
|
+
raise ArgumentError, "Could not parse given input. Please use a GeoJSON polygon."
|
163
|
+
end
|
164
|
+
|
165
|
+
def invalid_coordinates!
|
166
|
+
raise ArgumentError, "Could not parse given coordinates."
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
data/lib/h3/hierarchy.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
module H3
|
2
|
+
# Hierarchical grid functions.
|
3
|
+
#
|
4
|
+
# @see https://uber.github.io/h3/#/documentation/api-reference/hierarchy
|
5
|
+
module Hierarchy
|
6
|
+
extend H3::Bindings::Base
|
7
|
+
|
8
|
+
# @!method h3_to_parent(h3_index, parent_resolution)
|
9
|
+
#
|
10
|
+
# Derive the parent hexagon which contains the hexagon at the given H3 index.
|
11
|
+
#
|
12
|
+
# @param [Integer] h3_index A valid H3 index.
|
13
|
+
# @param [Integer] parent_resoluton The desired resolution of the parent hexagon.
|
14
|
+
#
|
15
|
+
# @example Find the parent hexagon for a H3 index.
|
16
|
+
# H3.h3_to_parent(613196570357137407, 6)
|
17
|
+
# 604189371209351167
|
18
|
+
#
|
19
|
+
# @return [Integer] H3 index of parent hexagon.
|
20
|
+
attach_function :h3_to_parent, :h3ToParent, [ :h3_index, :int ], :h3_index
|
21
|
+
|
22
|
+
# @!method max_h3_to_children_size(h3_index, child_resolution)
|
23
|
+
#
|
24
|
+
# Derive maximum number of child hexagons possible at given resolution.
|
25
|
+
#
|
26
|
+
# @param [Integer] h3_index A valid H3 index.
|
27
|
+
# @param [Integer] child_resoluton The desired resolution of the child hexagons.
|
28
|
+
#
|
29
|
+
# @example Derive maximum number of child hexagons.
|
30
|
+
# H3.max_h3_to_children_size(613196570357137407, 10)
|
31
|
+
# 49
|
32
|
+
#
|
33
|
+
# @return [Integer] Maximum number of child hexagons possible at given resolution.
|
34
|
+
attach_function :max_h3_to_children_size, :maxH3ToChildrenSize, [ :h3_index, :int ], :int
|
35
|
+
|
36
|
+
# Derive child hexagons contained within the hexagon at the given H3 index.
|
37
|
+
#
|
38
|
+
# @param [Integer] h3_index A valid H3 index.
|
39
|
+
# @param [Integer] child_resolution The desired resolution of hexagons returned.
|
40
|
+
#
|
41
|
+
# @example Find the child hexagons for a H3 index.
|
42
|
+
# H3.h3_to_children(613196570357137407, 9)
|
43
|
+
# [
|
44
|
+
# 617700169982672895, 617700169982935039, 617700169983197183, 617700169983459327,
|
45
|
+
# 617700169983721471, 617700169983983615, 617700169984245759
|
46
|
+
# ]
|
47
|
+
#
|
48
|
+
# @return [Array<Integer>] H3 indexes of child hexagons.
|
49
|
+
def h3_to_children(h3_index, child_resolution)
|
50
|
+
max_children = max_h3_to_children_size(h3_index, child_resolution)
|
51
|
+
h3_children = FFI::MemoryPointer.new(H3_INDEX, max_children)
|
52
|
+
Bindings::Private.h3_to_children(h3_index, child_resolution, h3_children)
|
53
|
+
h3_children.read_array_of_ulong_long(max_children).reject(&:zero?)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Find the maximum uncompacted size of the given set of H3 indexes.
|
57
|
+
#
|
58
|
+
# @param [Array<Integer>] compacted_set An array of valid H3 indexes.
|
59
|
+
# @param [Integer] resolution The desired resolution to uncompact to.
|
60
|
+
#
|
61
|
+
# @example Find the maximum uncompacted size of the given set.
|
62
|
+
# h3_set = [
|
63
|
+
# 617700440093229055, 617700440092704767, 617700440100569087, 617700440013012991,
|
64
|
+
# 617700440013275135, 617700440092180479, 617700440091656191, 617700440092966911,
|
65
|
+
# 617700440100831231, 617700440100044799, 617700440101617663, 617700440081956863,
|
66
|
+
# 613196840447246335
|
67
|
+
# ]
|
68
|
+
# H3.max_uncompact_size(h3_set, 10)
|
69
|
+
# 133
|
70
|
+
#
|
71
|
+
# @raise [ArgumentError] Given resolution is invalid for h3_set.
|
72
|
+
#
|
73
|
+
# @return [Integer] Maximum size of uncompacted set.
|
74
|
+
def max_uncompact_size(compacted_set, resolution)
|
75
|
+
compacted_set = compacted_set.uniq
|
76
|
+
FFI::MemoryPointer.new(H3_INDEX, compacted_set.size) do |hexagons_ptr|
|
77
|
+
hexagons_ptr.write_array_of_ulong_long(compacted_set)
|
78
|
+
size = Bindings::Private.max_uncompact_size(hexagons_ptr, compacted_set.size, resolution)
|
79
|
+
raise(ArgumentError, "Couldn't estimate size. Invalid resolution?") if size < 0
|
80
|
+
return size
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Compact a set of H3 indexes as best as possible.
|
85
|
+
#
|
86
|
+
# In the case where the set cannot be compacted, the set is returned unchanged.
|
87
|
+
#
|
88
|
+
# @param [Array<Integer>] h3_set An array of valid H3 indexes.
|
89
|
+
#
|
90
|
+
# @example Compact the given set.
|
91
|
+
# h3_set = [
|
92
|
+
# 617700440073043967, 617700440072781823, 617700440073568255, 617700440093229055,
|
93
|
+
# 617700440092704767, 617700440100569087, 617700440074092543, 617700440073830399,
|
94
|
+
# 617700440074354687, 617700440073306111, 617700440013012991, 617700440013275135,
|
95
|
+
# 617700440092180479, 617700440091656191, 617700440092966911, 617700440100831231,
|
96
|
+
# 617700440100044799, 617700440101617663, 617700440081956863
|
97
|
+
# ]
|
98
|
+
# H3.compact(h3_set)
|
99
|
+
# [
|
100
|
+
# 617700440093229055, 617700440092704767, 617700440100569087, 617700440013012991,
|
101
|
+
# 617700440013275135, 617700440092180479, 617700440091656191, 617700440092966911,
|
102
|
+
# 617700440100831231, 617700440100044799, 617700440101617663, 617700440081956863,
|
103
|
+
# 613196840447246335
|
104
|
+
# ]
|
105
|
+
#
|
106
|
+
# @raise [RuntimeError] Couldn't attempt to compact given H3 indexes.
|
107
|
+
#
|
108
|
+
# @return [Array<Integer>] Compacted set of H3 indexes.
|
109
|
+
def compact(h3_set)
|
110
|
+
h3_set = h3_set.uniq
|
111
|
+
failure = false
|
112
|
+
out = FFI::MemoryPointer.new(H3_INDEX, h3_set.size)
|
113
|
+
FFI::MemoryPointer.new(H3_INDEX, h3_set.size) do |hexagons_ptr|
|
114
|
+
hexagons_ptr.write_array_of_ulong_long(h3_set)
|
115
|
+
failure = Bindings::Private.compact(hexagons_ptr, out, h3_set.size)
|
116
|
+
end
|
117
|
+
|
118
|
+
raise "Couldn't compact given indexes" if failure
|
119
|
+
out.read_array_of_ulong_long(h3_set.size).reject(&:zero?)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Uncompact a set of H3 indexes to the given resolution.
|
123
|
+
#
|
124
|
+
# @param [Array<Integer>] compacted_set An array of valid H3 indexes.
|
125
|
+
# @param [Integer] resolution The desired resolution to uncompact to.
|
126
|
+
#
|
127
|
+
# @example Compact the given set.
|
128
|
+
# h3_set = [
|
129
|
+
# 617700440093229055, 617700440092704767, 617700440100569087, 617700440013012991,
|
130
|
+
# 617700440013275135, 617700440092180479, 617700440091656191, 617700440092966911,
|
131
|
+
# 617700440100831231, 617700440100044799, 617700440101617663, 617700440081956863,
|
132
|
+
# 613196840447246335
|
133
|
+
# ]
|
134
|
+
# H3.uncompact(h3_set)
|
135
|
+
# [
|
136
|
+
# 617700440093229055, 617700440092704767, 617700440100569087, 617700440013012991,
|
137
|
+
# 617700440013275135, 617700440092180479, 617700440091656191, 617700440092966911,
|
138
|
+
# 617700440100831231, 617700440100044799, 617700440101617663, 617700440081956863,
|
139
|
+
# 617700440072781823, 617700440073043967, 617700440073306111, 617700440073568255,
|
140
|
+
# 617700440073830399, 617700440074092543, 617700440074354687
|
141
|
+
# ]
|
142
|
+
#
|
143
|
+
# @raise [RuntimeError] Couldn't attempt to umcompact H3 indexes.
|
144
|
+
#
|
145
|
+
# @return [Array<Integer>] Uncompacted set of H3 indexes.
|
146
|
+
def uncompact(compacted_set, resolution)
|
147
|
+
max_size = max_uncompact_size(compacted_set, resolution)
|
148
|
+
|
149
|
+
failure = false
|
150
|
+
out = FFI::MemoryPointer.new(H3_INDEX, max_size)
|
151
|
+
FFI::MemoryPointer.new(H3_INDEX, compacted_set.size) do |hexagons_ptr|
|
152
|
+
hexagons_ptr.write_array_of_ulong_long(compacted_set)
|
153
|
+
failure = Bindings::Private.uncompact(hexagons_ptr, compacted_set.size, out, max_size, resolution)
|
154
|
+
end
|
155
|
+
|
156
|
+
raise "Couldn't uncompact given indexes" if failure
|
157
|
+
out.read_array_of_ulong_long(max_size).reject(&:zero?)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|