• Stars
    star
    122
  • Rank 292,031 (Top 6 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 8 years ago
  • Updated almost 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Simple yet useful Geo Coordinates class for Ruby

Geo::Coord—simple geo coordinates class for Ruby

Gem Version Build Status Coverage Status

Geo::Coord is a basic class representing [latitude, longitude] pair and incapsulating related concepts and calculations.

Features

  • Simple storage for geographical latitude & longitude pair;
  • Easily converted from/to many different representations (arrays, hashes, degrees/minutes/seconds, radians, strings with different formatting);
  • Geodesy math (distances, directions, endpoints) via precise Vincenty formula.

Reasons

Geo coordinates are, in fact, one of basic types in XXI century programming.

This gem is a (desperate) attempt to provide such a "basic" type ready to be dropped into any of Ruby code, to unify all different LatLng or Point or Location classes in existing geography and geo-aware gems for easy data exchange and natural usage.

As an independent gem, this attempt is doomed by design, but why not to try?..

Initially, I've done this work as a proposal for inclusion in Ruby's standard library, but it was not met very well. So, now I'm releasing it as a gem to be available at least for my own other projects.

You can read my initial proposal here and discussion in Ruby tracker there.

I still have a small hope it would be part of stdlib once, that's why I preserve the style of specs (outdated rspec, but compatible with mspec used for standard library) and docs (yard in RDoc-compatibility mode).

Installation

As usual: gem install geo_coord or add gem "geo_coord", require: "geo/coord" to your Gemfile.

Usage

Creation

require 'geo/coord'

# From lat/lng pair:
g = Geo::Coord.new(50.004444, 36.231389)
# => #<Geo::Coord 50°0'16"N 36°13'53"E>

# Or using keyword arguments form:
g = Geo::Coord.new(lat: 50.004444, lng: 36.231389)
# => #<Geo::Coord 50°0'16"N 36°13'53"E>

# Keyword arguments also allow creation of Coord from components:
g = Geo::Coord.new(latd: 50, latm: 0, lats: 16, lath: 'N', lngd: 36, lngm: 13, lngs: 53, lngh: 'E')
# => #<Geo::Coord 50°0'16"N 36°13'53"E>

For parsing API responses you'd like to use from_h, which accepts String and Symbol keys, any letter case, and knows synonyms (lng/lon/longitude):

g = Geo::Coord.from_h('LAT' => 50.004444, 'LON' => 36.231389)
# => #<Geo::Coord 50°0'16"N 36°13'53"E>

For math, you'd probably like to be able to initialize Coord with radians rather than degrees:

g = Geo::Coord.from_rad(0.8727421884291233, 0.6323570306208558)
# => #<Geo::Coord 50°0'16"N 36°13'53"E>

There's also family of string parsing methods, with different applicability:

# Tries to parse (lat, lng) pair:
g = Geo::Coord.parse_ll('50.004444, 36.231389')
# => #<Geo::Coord 50°0'16"N 36°13'53"E>

# Tries to parse degrees/minutes/seconds:
g = Geo::Coord.parse_dms('50° 0′ 16″ N, 36° 13′ 53″ E')
# => #<Geo::Coord 50°0'16"N 36°13'53"E>

# Tries to do best guess:
g = Geo::Coord.parse('50.004444, 36.231389')
# => #<Geo::Coord 50°0'16"N 36°13'53"E>
g = Geo::Coord.parse('50° 0′ 16″ N, 36° 13′ 53″ E')
# => #<Geo::Coord 50°0'16"N 36°13'53"E>

# Allows user to provide pattern:
g = Geo::Coord.strpcoord('50.004444, 36.231389', '%lat, %lng')
# => #<Geo::Coord 50°0'16"N 36°13'53"E>

Pattern language description

Examining the object

Having Coord object, you can get its properties:

g = Geo::Coord.new(50.004444, 36.231389)
g.lat # => 50.004444
g.latd # => 50 -- latitude degrees
g.lath # => N -- latitude hemisphere
g.lngh # => E -- longitude hemishpere
g.phi  # => 0.8727421884291233 -- longitude in radians
g.latdms # => [50, 0, 15.998400000011316, "N"]
# ...and so on

Formatting and converting

g.to_s              # => "50°0'16\"N 36°13'53\"E"
g.to_s(dms: false)  # => "50.004444,36.231389"
g.strfcoord('%latd°%latm′%lats″%lath %lngd°%lngm′%lngs″%lngh')
# => "50°0′16″N 36°13′53″E"

g.to_h(lat: 'LAT', lng: 'LON') # => {'LAT'=>50.004444, 'LON'=>36.231389}

Geodesy math

kharkiv = Geo::Coord.new(50.004444, 36.231389)
kyiv = Geo::Coord.new(50.45, 30.523333)

kharkiv.distance(kyiv) # => 410211.22377421556
kharkiv.azimuth(kyiv) # => 279.12614358262067
kharkiv.endpoint(410_211, 280) # => #<Geo::Coord 50°30'22"N 30°31'53"E>

Full API Docs

Design decisions

While designing Geo library, my reference point was standard Time class (and, to lesser extent, Date/DateTime). It has these responsibilities:

  • stores data in simple internal form;
  • helps to parse and format data to and from strings;
  • provides easy access to logical components of data;
  • allows most simple and unambiguous calculations.

Namespace name: The gem takes pretty short and generic top-level namespace name Geo, but creates only one class inside it: Geo::Coord.

Main type name: as far as I can see, there's no good singular name for (lat, lng) pair concept. In different libraries, there can be seen names like LatLng, or Location, or Point; and in natural language just "coordinates" used frequently. I propose the name Coord, which is pretty short, easy to remember, demonstrates intentions (and looks like singular, so you can have "one coord object" and "array of coords", which is not 100% linguistically correct, yet convenient). Alternative Point name seems to be too ambiguous, being used in many contexts.

Geo::Coord object is immutable, there's no semantical sense in location.latitude = ... or something like this.

Units: Geo calculations (just like Time calculations) provide no units options, just returning numbers measured in "default" units: metres for distances (as they are SI unit) and degrees for azimuth. Latitude and longitude are stored in degrees, but radians values accessors are provided (being widely used in geodesy math).

Internal storage: Since ver 0.1.0, latitude and longitude stored internally as an instances of BigDecimal. While having some memory and performance downsides, this datatype provides correctness of conversions between floating point & deg-min-sec representations:

# 33.3 should be 33°18'00"
# Float:
33.3 * 60 % 60 # => 17.999999999999773 minutes
# BigDecimal
BigDecimal(33.3, 10) * 60 % 60 # => 0.18e2

All coordinates and calculations are thought to be in WGS 84 coordinates reference system, being current standard for maps and GPS.

There's introduced a concept of globe used internally for calculations. Only generic (sphere) and Earth globes are implemented, but for 2010th I feel like the current design of basic types should take in consideration possibility of writing Ruby scripts for Mars maps analysis. Only one geodesy formula is implemented (Vincenty, generally considered one of the most precise), as for standard library class it considered unnecessary to provide a user with geodesy formulae options.

No map projection math was added into the current gem, but it may be a good direction for further work. No elevation data considered either.

Author

Victor Shepelev

License

MIT.

More Repositories

1

wikipedia_ql

Query language for efficient data extraction from Wikipedia
Python
357
star
2

time_math2

Small library for operations with time steps (like "next day", "floor to hour" and so on)
Ruby
278
star
3

spylls

Pure Python spell-checker, (almost) full port of Hunspell
Python
265
star
4

worldize

Simple coloured countries drawing
Ruby
258
star
5

time_calc

Simple time arithmetics in a modern, readable, idiomatic, no-"magic" Ruby.
Ruby
213
star
6

hm

Idiomatic Ruby hash transformations
Ruby
129
star
7

any_good

Is this gem any good?
Ruby
119
star
8

wheretz

Fast and precise time zone by geo coordinates lookup
Ruby
99
star
9

good-value-object

Ruby Value Object conventions
Ruby
93
star
10

magic_cloud

Simple pretty word cloud for Ruby
Ruby
85
star
11

the_schema_is

ActiveRecord schema annotations done right
Ruby
70
star
12

saharspec

RSpec sugar to DRY your specs
Ruby
67
star
13

yard-junk

Get rid of the junk in your YARD docs
Ruby
67
star
14

whatthegem

Ruby gem information, stats and usage for your terminal
Ruby
62
star
15

sho

Experimental post-framework view library
Ruby
45
star
16

xkcdize

XKCD-like picture distortion in Ruby and RMagick
Ruby
45
star
17

clio

Clio — better Friendfeed backup tool
JavaScript
39
star
18

ruby_as_apl

Conway's game of life in one statement of idiomatic Ruby... ported from APL
Ruby
35
star
19

delegates

delegate :methods, to: :target, extracted from ActiveSupport
Ruby
32
star
20

dokaz

Use your documentation as a specification: parse and evaluate ruby code from markdown
Ruby
32
star
21

rubyseeds

Ruby core extensions repository (not a gem!)
Ruby
28
star
22

lmsa

Let's Make Something Awesome! — project ideas repo for mentees
Ruby
26
star
23

drosterize

Self-replicating images with Ruby & RMagick
Ruby
26
star
24

linkhum

URL auto-linker with reasonable and humane behavior
Ruby
25
star
25

object_enumerate

Object#enumerate Ruby core proposal demo. Merged in Ruby 2.7 as Enumerator.produce
Ruby
19
star
26

procme

Fun with proc
Ruby
17
star
27

my-ruby-contributions

Moved to https://zverok.github.io/ruby.html
Ruby
17
star
28

fstrings

Python-alike fstrings (formatting strings) for Ruby
Ruby
14
star
29

grok-shan-shui

Grok {Shan, Shui}*: Advent of understanding the generative art
HTML
14
star
30

did_you

Ruby version-agnostic wrapper for did_you_mean gem
Ruby
10
star
31

idempotent_enumerable

IdempotentEnumerable is like Enumerable but preserves original collection class
Ruby
8
star
32

enumerator_generate

Enumerator#generate Ruby core proposal demo
Ruby
4
star
33

grokability

Grokability -- step after Readability
JavaScript
4
star
34

clio-web

Online version of FrF backup
Ruby
3
star
35

lastic

ElasticSearch DSL which erases all the complexity
Ruby
3
star
36

bloxl

Hi-level Excel-2007 reports DSL
Ruby
3
star
37

confucius

Simple framework-agnostic configuration for any Ruby app
Ruby
2
star
38

zverok.github.io

HTML
2
star
39

sequel_marginalia

Port of 37 signals marginalia for use with Sequel
Ruby
2
star
40

culturecodes

parsers for http://friendfeed.com/culturecodes
Ruby
2
star
41

uberdictionary

HTML/JS client to several En-Ru dictionaries
JavaScript
2
star
42

pattern-matching-prototype

Showcase of possible Ruby core language pattern matching
Ruby
2
star
43

cobb

Cobb is Yet Another Web Scraper, named after Firefly's Jayne Cobb
Ruby
1
star
44

matchish

An exercise for pattern matching in Ruby
Ruby
1
star