Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v401 Update #85

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
PATH
remote: .
specs:
h3 (3.7.2)
h3 (4.0.0)
ffi (~> 1.9)
rgeo-geojson (~> 2.1)
zeitwerk (~> 2.5)

GEM
remote: https://rubygems.org/
specs:
coderay (1.1.3)
diff-lcs (1.5.0)
ffi (1.15.5)
method_source (1.0.0)
pry (0.14.1)
coderay (~> 1.1)
method_source (~> 1.0)
rake (13.0.6)
rgeo (2.3.0)
rgeo (2.4.0)
rgeo-geojson (2.1.1)
rgeo (>= 1.0.0)
rspec (3.11.0)
Expand All @@ -21,26 +26,27 @@ GEM
rspec-mocks (~> 3.11.0)
rspec-core (3.11.0)
rspec-support (~> 3.11.0)
rspec-expectations (3.11.0)
rspec-expectations (3.11.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.11.0)
rspec-mocks (3.11.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.11.0)
rspec-support (3.11.0)
rspec-support (3.11.1)
webrick (1.7.0)
yard (0.9.28)
webrick (~> 1.7.0)
zeitwerk (2.6.0)
zeitwerk (2.6.1)

PLATFORMS
ruby

DEPENDENCIES
h3!
pry (~> 0.14)
rake (~> 13.0)
rspec (~> 3.8)
yard (~> 0.9)

BUNDLED WITH
2.2.22
2.1.4
7 changes: 2 additions & 5 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ RSpec::Core::RakeTask.new(:spec)

desc "Build H3 C library"
task :build do
unless File.exist?("ext/h3/src/Makefile")
unless File.exist?("ext/h3/src/build/Makefile")
`git submodule update --init --recursive`
print "Building h3..."
`cd ext/h3; make > /dev/null 2>&1`
Expand All @@ -13,10 +13,7 @@ end

desc "Remove compiled H3 library"
task :clean do
File.delete("ext/h3/src/Makefile") if File.exist?("ext/h3/src/Makefile")
FileUtils.remove_dir("ext/h3/src/bin") if Dir.exist?("ext/h3/src/bin")
FileUtils.remove_dir("ext/h3/src/generated") if Dir.exist?("ext/h3/src/generated")
FileUtils.remove_dir("ext/h3/src/lib") if Dir.exist?("ext/h3/src/lib")
FileUtils.remove_dir("ext/h3/src/build") if Dir.exist?("ext/h3/src/build")
end

task spec: :build
Expand Down
4 changes: 2 additions & 2 deletions ext/h3/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
make:
cd src; cmake . -DBUILD_SHARED_LIBS=true -DBUILD_FILTERS=OFF -DBUILD_BENCHMARKS=OFF; make
cd src; mkdir build; cd build; cmake -DBUILD_SHARED_LIBS=true -DCMAKE_BUILD_TYPE=Release ..; make
install:
: # do nothing, we'll load the lib directly
clean:
: # do nothing, cleanup happens when gem uninstalled
rm -rf build
2 changes: 2 additions & 0 deletions h3.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Gem::Specification.new do |spec|
spec.version = H3::VERSION
spec.licenses = ["MIT"]
spec.summary = "C Bindings for Uber's H3 library"

spec.homepage = "https://github.com/seanhandley/h3_ruby"
spec.authors = ["Sean Handley", "Xavier Noria", "Lachlan Laycock"]
spec.email = "[email protected]"
Expand All @@ -20,6 +21,7 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "rake", "~> 13.0"
spec.add_development_dependency "rspec", "~> 3.8"
spec.add_development_dependency "yard", "~> 0.9"
spec.add_development_dependency "pry", "~> 0.14"

spec.extensions << "ext/h3/extconf.rb"
end
3 changes: 2 additions & 1 deletion lib/h3/bindings/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ module Bindings
# When extended, this module sets up FFI to use the H3 C library.
module Base
def self.extended(base)
lib_path = File.expand_path(__dir__ + "/../../../ext/h3/src/lib")
lib_path = File.expand_path(__dir__ + "/../../../ext/h3/src/build/lib")
base.extend FFI::Library
base.extend Gem::Deprecate
base.include Structs
base.include Types
base.ffi_lib ["#{lib_path}/libh3.dylib", "#{lib_path}/libh3.so"]
base.typedef :ulong_long, :h3_index
base.typedef :int, :k_distance
base.typedef :uint, :h3_error_code
end

def attach_predicate_function(name, *args)
Expand Down
39 changes: 39 additions & 0 deletions lib/h3/bindings/error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module H3
module Bindings
module Error
class FailedError < StandardError ; end
class DomainError < StandardError ; end
class LatLngDomainError < StandardError ; end
class ResolutionDomainError < StandardError ; end
class CellInvalidError < StandardError ; end
class DirectedEdgeInvalidError < StandardError ; end
class UndirectedEdgeInvalidError < StandardError ; end
class VertexInvalidError < StandardError ; end
class PentagonDistortionError < StandardError ; end
class DuplicateInputError < StandardError ; end
class NotNeighborsError < StandardError ; end
class ResolutionMismatchError < StandardError ; end
class MemoryAllocationError < StandardError ; end
class MemoryBoundsError < StandardError ; end

def self.raise_error(code)
case code
when 1 then raise FailedError
when 2 then raise DomainError
when 3 then raise LatLngDomainError
when 4 then raise ResolutionDomainError
when 5 then raise CellInvalidError
when 6 then raise DirectedEdgeInvalidError
when 7 then raise UndirectedEdgeInvalidError
when 8 then raise VertexInvalidError
when 9 then raise PentagonDistortionError
when 10 then raise DuplicateInputError
when 11 then raise NotNeighborsError
when 12 then raise ResolutionMismatchError
when 13 then raise MemoryAllocationError
when 14 then raise MemoryBoundsError
end
end
end
end
end
114 changes: 64 additions & 50 deletions lib/h3/bindings/private.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,71 @@ module Bindings
module Private
extend H3::Bindings::Base

attach_function :compact, [H3IndexesIn, H3IndexesOut, :size_t], :bool
attach_function :destroy_linked_polygon, :destroyLinkedPolygon, [LinkedGeoPolygon], :void
attach_function :geo_to_h3, :geoToH3, [GeoCoord, Resolution], :h3_index
attach_function :get_pentagon_indexes, :getPentagonIndexes, [:int, H3IndexesOut], :void
attach_function :h3_faces, :h3GetFaces, %i[h3_index buffer_out], :void
attach_function :h3_indexes_from_unidirectional_edge,
:getH3IndexesFromUnidirectionalEdge,
[:h3_index, H3IndexesOut], :void
attach_function :h3_line, :h3Line, [:h3_index, :h3_index, H3IndexesOut], :int
attach_function :h3_unidirectional_edges_from_hexagon,
:getH3UnidirectionalEdgesFromHexagon,
[:h3_index, H3IndexesOut], :void
attach_function :h3_set_to_linked_geo,
:h3SetToLinkedGeo,
[H3IndexesIn, :size_t, LinkedGeoPolygon],
:void
attach_function :h3_to_children, :h3ToChildren, [:h3_index, Resolution, H3IndexesOut], :void
attach_function :h3_to_geo, :h3ToGeo, [:h3_index, GeoCoord], :void
attach_function :h3_to_string, :h3ToString, %i[h3_index buffer_out size_t], :void
def self.safe_call(out_type, method, *in_args)
out = FFI::MemoryPointer.new(out_type)
send(method, *in_args + [out]).tap do |code|
Error::raise_error(code) unless code.zero?
end
out.send("read_#{out_type}".to_sym)
end

attach_function :cellToParent, [:h3_index, Resolution, H3Index], :h3_error_code
attach_function :compactCells, [H3IndexesIn, H3IndexesOut, :int64], :h3_error_code
# attach_function :destroy_linked_polygon, :destroyLinkedPolygon, [LinkedGeoPolygon], :void
attach_function :edge_length_km, :getHexagonEdgeLengthAvgKm, [Resolution, :pointer], :h3_error_code
attach_function :from_string, :stringToH3, %i[string pointer], :h3_error_code
attach_function :geo_to_h3, :latLngToCell, [LatLng, Resolution, :pointer], :h3_error_code
# attach_function :get_pentagon_indexes, :getPentagonIndexes, [:int, H3IndexesOut], :void
attach_function :hexagon_count, :getNumCells, [Resolution, :pointer], :h3_error_code
attach_function :h3_faces, :getIcosahedronFaces, %i[h3_index buffer_out], :h3_error_code
# attach_function :h3_indexes_from_unidirectional_edge,
# :getH3IndexesFromUnidirectionalEdge,
# [:h3_index, H3IndexesOut], :void
# attach_function :h3_line, :h3Line, [:h3_index, :h3_index, H3IndexesOut], :int
# attach_function :h3_unidirectional_edges_from_hexagon,
# :getH3UnidirectionalEdgesFromHexagon,
# [:h3_index, H3IndexesOut], :void
# attach_function :h3_set_to_linked_geo,
# :h3SetToLinkedGeo,
# [H3IndexesIn, :size_t, LinkedGeoPolygon],
# :void
attach_function :h3_to_children, :cellToChildren, [:h3_index, Resolution, H3IndexesOut], :h3_error_code
attach_function :h3_to_geo, :cellToLatLng, [:h3_index, LatLng], :h3_error_code
attach_function :h3_to_string, :h3ToString, %i[h3_index buffer_out size_t], :h3_error_code
attach_function :h3_to_geo_boundary,
:h3ToGeoBoundary,
[:h3_index, GeoBoundary],
:void
attach_function :h3_unidirectional_edge_boundary,
:getH3UnidirectionalEdgeBoundary,
[:h3_index, GeoBoundary], :void
attach_function :hex_range, :hexRange, [:h3_index, :k_distance, H3IndexesOut], :bool
attach_function :hex_range_distances,
:hexRangeDistances,
[:h3_index, :k_distance, H3IndexesOut, :buffer_out], :bool
attach_function :hex_ranges,
:hexRanges,
[H3IndexesIn, :size_t, :k_distance, H3IndexesOut],
:bool
attach_function :hex_ring, :hexRing, [:h3_index, :k_distance, H3IndexesOut], :bool
attach_function :k_ring, :kRing, [:h3_index, :k_distance, H3IndexesOut], :void
attach_function :k_ring_distances,
:kRingDistances,
[:h3_index, :k_distance, H3IndexesOut, :buffer_out],
:bool
attach_function :max_polyfill_size,
:maxPolyfillSize,
[GeoPolygon, Resolution],
:int
attach_function :max_uncompact_size, :maxUncompactSize, [H3IndexesIn, :size_t, Resolution], :int
attach_function :point_distance_rads, :pointDistRads, [GeoCoord, GeoCoord], :double
attach_function :point_distance_km, :pointDistKm, [GeoCoord, GeoCoord], :double
attach_function :point_distance_m, :pointDistM, [GeoCoord, GeoCoord], :double
attach_function :polyfill, [GeoPolygon, Resolution, H3IndexesOut], :void
attach_function :res_0_indexes, :getRes0Indexes, [H3IndexesOut], :void
attach_function :uncompact, [H3IndexesIn, :size_t, H3IndexesOut, :size_t, Resolution], :bool
:cellToBoundary,
[:h3_index, CellBoundary],
:h3_error_code
# attach_function :h3_unidirectional_edge_boundary,
# :getH3UnidirectionalEdgeBoundary,
# [:h3_index, CellBoundary], :void
# attach_function :hex_range, :hexRange, [:h3_index, :k_distance, H3IndexesOut], :bool
# attach_function :hex_range_distances,
# :hexRangeDistances,
# [:h3_index, :k_distance, H3IndexesOut, :buffer_out], :bool
# attach_function :hex_ranges,
# :hexRanges,
# [H3IndexesIn, :size_t, :k_distance, H3IndexesOut],
# :bool
# attach_function :hex_ring, :hexRing, [:h3_index, :k_distance, H3IndexesOut], :bool
attach_function :k_ring, :gridDisk, [:h3_index, :k_distance, H3IndexesOut], :h3_error_code
# attach_function :k_ring_distances,
# :kRingDistances,
# [:h3_index, :k_distance, H3IndexesOut, :buffer_out],
# :bool
attach_function :max_children, :cellToChildrenSize, [:h3_index, Resolution, :pointer], :h3_error_code
attach_function :max_face_count, :maxFaceCount, %i[h3_index pointer], :h3_error_code
# attach_function :max_polyfill_size,
# :maxPolyfillSize,
# [GeoPolygon, Resolution],
# :int
attach_function :max_uncompact_size, :uncompactCellsSize, [H3IndexesIn, :int64, Resolution, :pointer], :h3_error_code
# attach_function :point_distance_rads, :pointDistRads, [GeoCoord, GeoCoord], :double
# attach_function :point_distance_km, :pointDistKm, [GeoCoord, GeoCoord], :double
# attach_function :point_distance_m, :pointDistM, [GeoCoord, GeoCoord], :double
# attach_function :polyfill, [GeoPolygon, Resolution, H3IndexesOut], :void
attach_function :res_0_indexes, :getRes0Cells, [H3IndexesOut], :h3_error_code
attach_function :uncompactCells, [H3IndexesIn, :size_t, H3IndexesOut, :size_t, Resolution], :h3_error_code
end
end
end
8 changes: 4 additions & 4 deletions lib/h3/bindings/structs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ module Bindings
module Structs
extend FFI::Library

class GeoCoord < FFI::Struct
class LatLng < FFI::Struct
layout :lat, :double,
:lon, :double
end

class GeoBoundary < FFI::Struct
class CellBoundary < FFI::Struct
layout :num_verts, :int,
:verts, [GeoCoord, 10] # array of GeoCoord structs (must be fixed length)
:verts, [LatLng, 10] # array of GeoCoord structs (must be fixed length)
end

class GeoFence < FFI::Struct
Expand All @@ -34,7 +34,7 @@ class GeoMultiPolygon < FFI::Struct
end

class LinkedGeoCoord < FFI::Struct
layout :vertex, GeoCoord,
layout :vertex, LatLng,
:next, LinkedGeoCoord.ptr
end

Expand Down
19 changes: 18 additions & 1 deletion lib/h3/bindings/types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,29 @@ def to_native(value, _context)
private

def failure
raise ArgumentError,
raise Error::ResolutionDomainError,
"resolution must be between #{RES_RANGE.first} and #{RES_RANGE.last}"
end
end
end

class H3Index
extend FFI::DataConverter
native_type FFI::Type::POINTER

def initialize(value)
ptr.write(value)
end

def size
FFI.type_size(FFI::Type::ULONG_LONG)
end

def ptr
@ptr ||= FFI::MemoryPointer.new(:ulong_long)
end
end

class H3IndexesIn
extend FFI::DataConverter
native_type FFI::Type::POINTER
Expand Down
Loading