seanhandley/h3_ruby

View on GitHub
lib/h3/indexing.rb

Summary

Maintainability
A
0 mins
Test Coverage
module H3
  # Indexing functions.
  #
  # Coordinates are returned in degrees, in the form
  #
  #   [latitude, longitude]
  #
  # @see https://uber.github.io/h3/#/documentation/api-reference/indexing
  module Indexing
    extend H3::Bindings::Base
    # Derive H3 index for the given set of coordinates.
    #
    # @param [Array<Integer>] coords A coordinate pair.
    # @param [Integer] resolution The desired resolution of the H3 index.
    #
    # @example Derive the H3 index for the given coordinates.
    #   H3.from_geo_coordinates([52.24630137198303, -1.7358398437499998], 9)
    #   617439284584775679
    #
    # @raise [ArgumentError] If coordinates are invalid.
    #
    # @return [Integer] H3 index.
    def from_geo_coordinates(coords, resolution)
      raise ArgumentError unless coords.is_a?(Array) && coords.count == 2

      lat, lon = coords

      if lat > 90 || lat < -90 || lon > 180 || lon < -180
        raise(ArgumentError, "Invalid coordinates")
      end

      coords = GeoCoord.new
      coords[:lat] = degs_to_rads(lat)
      coords[:lon] = degs_to_rads(lon)
      Bindings::Private.geo_to_h3(coords, resolution)
    end

    # Derive coordinates for a given H3 index.
    #
    # The coordinates map to the centre of the hexagon at the given index.
    #
    # @param [Integer] h3_index A valid H3 index.
    #
    # @example Derive the central coordinates for the given H3 index.
    #   H3.to_geo_coordinates(617439284584775679)
    #   [52.245519061399506, -1.7363137757391423]
    #
    # @return [Array<Integer>] A coordinate pair.
    def to_geo_coordinates(h3_index)
      coords = GeoCoord.new
      Bindings::Private.h3_to_geo(h3_index, coords)
      [rads_to_degs(coords[:lat]), rads_to_degs(coords[:lon])]
    end

    # Derive the geographical boundary as coordinates for a given H3 index.
    #
    # This will be a set of 6 coordinate pairs matching the vertexes of the
    # hexagon represented by the given H3 index.
    #
    # If the H3 index is a pentagon, there will be only 5 coordinate pairs returned.
    #
    # @param [Integer] h3_index A valid H3 index.
    #
    # @example Derive the geographical boundary for the given H3 index.
    #   H3.to_boundary(617439284584775679)
    #   [
    #     [52.247260929171055, -1.736809158397472], [52.24625850761068, -1.7389279144996015],
    #     [52.244516619273476, -1.7384324668792375], [52.243777169245725, -1.7358184256304658],
    #     [52.24477956752282, -1.7336997597088104], [52.246521439109415, -1.7341950448552204]
    #   ]
    #
    # @return [Array<Array<Integer>>] An array of six coordinate pairs.
    def to_boundary(h3_index)
      geo_boundary = GeoBoundary.new
      Bindings::Private.h3_to_geo_boundary(h3_index, geo_boundary)
      geo_boundary[:verts].take(geo_boundary[:num_verts]).map do |d|
        [rads_to_degs(d[:lat]), rads_to_degs(d[:lon])]
      end
    end
  end
end