seanhandley/h3_ruby

View on GitHub
lib/h3/miscellaneous.rb

Summary

Maintainability
A
0 mins
Test Coverage
module H3
  # Miscellaneous functions.
  #
  # @see https://uber.github.io/h3/#/documentation/api-reference/miscellaneous
  module Miscellaneous
    extend H3::Bindings::Base

    # @!method degs_to_rads(degs)
    #
    # Convert a number expressed in degrees to its equivalent in radians.
    #
    # @param [Float] degs Value expressed in degrees.
    #
    # @example Convert degrees value to radians.
    #   H3.degs_to_rads(19.61922082086965)
    #   0.34242
    #
    # @return [Float] Value expressed in radians.
    attach_function :degs_to_rads, :degsToRads, %i[double], :double

    # @!method edge_length_km(resolution)
    #
    # Derive the length of a hexagon edge in kilometres at the given resolution.
    #
    # @param [Integer] resolution Resolution.
    #
    # @example Derive length of edge in kilometres
    #   H3.edge_length_km(3)
    #   59.81085794
    #
    # @return [Float] Length of edge in kilometres
    attach_function :edge_length_km, :edgeLengthKm, [Resolution], :double

    # @!method edge_length_m(resolution)
    #
    # Derive the length of a hexagon edge in metres at the given resolution.
    #
    # @param [Integer] resolution Resolution.
    #
    # @example Derive length of edge in metres
    #   H3.edge_length_m(6)
    #   3229.482772
    #
    # @return [Float] Length of edge in metres
    attach_function :edge_length_m, :edgeLengthM, [Resolution], :double

    # @!method hex_area_km2(resolution)
    #
    # Average hexagon area in square kilometres at the given resolution.
    #
    # @param [Integer] resolution Resolution.
    #
    # @example Find the square kilometre size at resolution 5
    #   H3.hex_area_km2(5)
    #   252.9033645
    #
    # @return [Float] Average hexagon area in square kilometres.
    attach_function :hex_area_km2, :hexAreaKm2, [Resolution], :double

    # @!method hex_area_m2(resolution)
    #
    # Average hexagon area in square metres at the given resolution.
    #
    # @param [Integer] resolution Resolution.
    #
    # @example Find the square metre size at resolution 10
    #   H3.hex_area_m2(10)
    #   15047.5
    #
    # @return [Float] Average hexagon area in square metres.
    attach_function :hex_area_m2, :hexAreaM2, [Resolution], :double

    # @!method hexagon_count(resolution)
    #
    # Number of unique H3 indexes at the given resolution.
    #
    # @param [Integer] resolution Resolution.
    #
    # @example Find number of hexagons at resolution 6
    #   H3.hexagon_count(6)
    #   14117882
    #
    # @return [Integer] Number of unique hexagons
    attach_function :hexagon_count, :numHexagons, [Resolution], :ulong_long

    # @!method rads_to_degs(rads)
    #
    # Convert a number expressed in radians to its equivalent in degrees.
    #
    # @param [Float] rads Value expressed in radians.
    #
    # @example Convert radians value to degrees.
    #   H3.rads_to_degs(0.34242)
    #   19.61922082086965
    #
    # @return [Float] Value expressed in degrees.
    attach_function :rads_to_degs, :radsToDegs, %i[double], :double

    # @!method base_cell_count
    #
    # Returns the number of resolution 0 hexagons (base cells).
    #
    # @example Return the number of base cells
    #    H3.base_cell_count
    #    122
    #
    # @return [Integer] The number of resolution 0 hexagons (base cells).
    attach_function :base_cell_count, :res0IndexCount, [], :int

    # @!method pentagon_count
    #
    # Number of pentagon H3 indexes per resolution.
    # This is always 12, but provided as a convenience.
    #
    # @example Return the number of pentagons
    #    H3.pentagon_count
    #    12
    #
    # @return [Integer] The number of pentagons per resolution.
    attach_function :pentagon_count, :pentagonIndexCount, [], :int

    # @!method cell_area_rads2
    #
    # Area of a given cell expressed in radians squared
    #
    # @example Return the area of the cell
    #    H3.cell_area_rads2(617700169958293503)
    #    2.6952182709835757e-09
    #
    # @return [Double] Area of cell in rads2
    attach_function :cell_area_rads2, :cellAreaRads2, %i[h3_index], :double

    # @!method cell_area_km2
    #
    # Area of a given cell expressed in km squared
    #
    # @example Return the area of the cell
    #    H3.cell_area_km2(617700169958293503)
    #    0.10939818864648902
    #
    # @return [Double] Area of cell in km2
    attach_function :cell_area_km2, :cellAreaKm2, %i[h3_index], :double

    # @!method cell_area_m2
    #
    # Area of a given cell expressed in metres squared
    #
    # @example Return the area of the cell
    #    H3.cell_area_m2(617700169958293503)
    #    109398.18864648901
    #
    # @return [Double] Area of cell in metres squared
    attach_function :cell_area_m2, :cellAreaM2, %i[h3_index], :double

    # @!method exact_edge_length_rads
    #
    # Exact length of edge in rads
    #
    # @example Return the edge length
    #    H3.exact_edge_length_rads(1266218516299644927)
    #    3.287684056071637e-05
    #
    # @return [Double] Edge length in rads
    attach_function :exact_edge_length_rads, :exactEdgeLengthRads, %i[h3_index], :double

    # @!method exact_edge_length_km
    #
    # Exact length of edge in kilometres
    #
    # @example Return the edge length
    #    H3.exact_edge_length_km(1266218516299644927)
    #    3.287684056071637e-05
    #
    # @return [Double] Edge length in kilometres
    attach_function :exact_edge_length_km, :exactEdgeLengthKm, %i[h3_index], :double

    # @!method exact_edge_length_m
    #
    # Exact length of edge in metres
    #
    # @example Return the edge length
    #    H3.exact_edge_length_m(1266218516299644927)
    #    3.287684056071637e-05
    #
    # @return [Double] Edge length in metres
    attach_function :exact_edge_length_m, :exactEdgeLengthM, %i[h3_index], :double

    # Returns the radians distance between two points.
    #
    # @example Return radians distance.
    #   H3.point_distance_rads([41.3964809, 2.160444], [41.3870609, 2.164917])
    #   0.00017453024784008713
    #
    # @return [Double] Radians distance between two points.
    def point_distance_rads(origin, destination)
      Bindings::Private.point_distance_rads(*build_geocoords(origin, destination))
    end

    # Returns the kilometres distance between two points.
    #
    # @example Return km distance.
    #   H3.point_distance_km([41.3964809, 2.160444], [41.3870609, 2.164917])
    #   1.1119334622766763
    #
    # @return [Double] KM distance between two points.
    def point_distance_km(origin, destination)
      Bindings::Private.point_distance_km(*build_geocoords(origin, destination))
    end

    # Returns the metre distance between two points.
    #
    # @example Return metre distance.
    #   H3.point_distance_m([41.3964809, 2.160444], [41.3870609, 2.164917])
    #   1111.9334622766764
    #
    # @return [Double] Metre distance between two points.
    def point_distance_m(origin, destination)
      Bindings::Private.point_distance_m(*build_geocoords(origin, destination))
    end

    # Returns all resolution 0 hexagons (base cells).
    #
    # @example Return all base cells.
    #   H3.base_cells
    #   [576495936675512319, 576531121047601151, ..., 580753245698260991]
    #
    # @return [Array<Integer>] All resolution 0 hexagons (base cells).
    def base_cells
      out = H3Indexes.of_size(base_cell_count)
      Bindings::Private.res_0_indexes(out)
      out.read
    end

    # Returns all pentagon indexes at the given resolution.
    #
    # @example Return all pentagons at resolution 4.
    #   H3.pentagons(4)
    #   [594615896891195391, 594967740612083711, ..., 598591730937233407]
    #
    # @return [Array<Integer>] All pentagon indexes at the given resolution.
    def pentagons(resolution)
      out = H3Indexes.of_size(pentagon_count)
      Bindings::Private.get_pentagon_indexes(resolution, out)
      out.read
    end

    private

    def build_geocoords(origin, destination)
      [origin, destination].inject([]) do |acc, coords|
        validate_coordinate(coords)

        geo_coord = GeoCoord.new
        lat, lon = coords
        geo_coord[:lat] = degs_to_rads(lat)
        geo_coord[:lon] = degs_to_rads(lon)
        acc << geo_coord
      end
    end

    def validate_coordinate(coords)
      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
    end
  end
end