The project is in a healthy, maintained state
Geographic point calculations including Haversine/Vincenty distance, bearing, midpoint, destination point, geohash encoding/decoding, cross-track distance, polygon containment, rhumb line navigation, bounding box, and DMS formatting. Zero dependencies.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

philiprehberger-geo_point

Tests Gem Version Last updated

Geographic coordinate operations with Haversine/Vincenty distance, geohash, rhumb lines, and bounding box

Requirements

  • Ruby >= 3.1

Installation

Add to your Gemfile:

gem "philiprehberger-geo_point"

Or install directly:

gem install philiprehberger-geo_point

Usage

require "philiprehberger/geo_point"

nyc = Philiprehberger::GeoPoint.point(40.7128, -74.0060)
london = Philiprehberger::GeoPoint.point(51.5074, -0.1278)

nyc.distance_to(london)  # => ~5570.0 (km)

Distance Units

nyc.distance_to(london, unit: :km)  # => ~5570.0
nyc.distance_to(london, unit: :mi)  # => ~3461.0
nyc.distance_to(london, unit: :m)   # => ~5570000.0
nyc.distance_to(london, unit: :nm)  # => ~3007.0

Vincenty Distance

nyc.distance_to(london, method: :vincenty)  # => ~5585.0 (ellipsoid-accurate)
nyc.distance_to(london, method: :haversine) # => ~5570.0 (spherical, default)

Bearing

nyc.bearing_to(london)  # => ~51.2 (degrees, 0-360)

Midpoint

mid = nyc.midpoint(london)
mid.lat  # => ~52.5
mid.lon  # => ~-36.0

Destination Point

dest = nyc.destination(51.2, 5570)  # bearing, distance in km
dest.lat  # => ~51.5
dest.lon  # => ~-0.1

Geohash

nyc.to_geohash                    # => "dr5ru6j2c62g" (precision 12)
nyc.to_geohash(precision: 6)     # => "dr5ru6"

point = Philiprehberger::GeoPoint.from_geohash("dr5ru6j2c62g")
point.lat  # => ~40.7128
point.lon  # => ~-74.0060

Cross-Track Distance

point = Philiprehberger::GeoPoint.point(1, 5)
path_start = Philiprehberger::GeoPoint.point(0, 0)
path_end = Philiprehberger::GeoPoint.point(0, 10)

point.cross_track_distance(path_start, path_end)  # => ~111.2 (km, positive = right of path)

Rhumb Lines

nyc.rhumb_distance_to(london)  # => ~5800.0 (km, constant-bearing route)
nyc.rhumb_bearing_to(london)   # => ~79.3 (degrees, constant bearing)

Polygon Containment

triangle = [
  Philiprehberger::GeoPoint.point(0, 0),
  Philiprehberger::GeoPoint.point(0, 10),
  Philiprehberger::GeoPoint.point(10, 5)
]

inside = Philiprehberger::GeoPoint.point(3, 5)
outside = Philiprehberger::GeoPoint.point(20, 20)

Philiprehberger::GeoPoint.inside_polygon?(inside, triangle)   # => true
Philiprehberger::GeoPoint.inside_polygon?(outside, triangle)  # => false

Bounding Box

box = Philiprehberger::GeoPoint::BoundingBox.around(nyc, 50)
box.contains?(nyc)     # => true
box.contains?(london)  # => false

DMS Formatting

nyc.to_dms  # => "40°42'46\"N 74°0'22\"W"
nyc.to_a    # => [40.7128, -74.0060]
nyc.to_h    # => {lat: 40.7128, lon: -74.0060}

API

GeoPoint

Method Description
.point(lat, lon) Create a new Point instance
.from_geohash(hash) Decode a geohash string to a Point at the center of the cell
.inside_polygon?(point, vertices) Check if a point is inside a polygon using ray-casting

GeoPoint::Point

Method Description
.new(lat, lon) Create point with coordinate validation (-90..90, -180..180)
#distance_to(other, unit: :km, method: :haversine) Distance via Haversine or Vincenty (:km, :mi, :m, :nm)
#bearing_to(other) Initial bearing in degrees (0-360)
#midpoint(other) Geographic midpoint between two points
#destination(bearing, distance, unit: :km) Point at given bearing and distance
#to_geohash(precision: 12) Encode point as a geohash string (precision 1-12)
#cross_track_distance(path_start, path_end, unit: :km) Perpendicular distance to great circle path
#rhumb_distance_to(other, unit: :km) Rhumb line (constant-bearing) distance
#rhumb_bearing_to(other) Rhumb line bearing in degrees (0-360)
#to_dms Format as degrees, minutes, seconds string
#to_a Return [lat, lon] array
#to_h Return {lat:, lon:} hash

GeoPoint::BoundingBox

Method Description
.around(point, radius, unit: :km) Create bounding box around a point
#contains?(point) Check if point is within the box
#to_a Return [min_lat, max_lat, min_lon, max_lon] array
#to_h Return hash with all bounds

Development

bundle install
bundle exec rspec
bundle exec rubocop

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT