Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add nautical miles to units

  • Loading branch information...
commit 641eb451e23b584f65ef2c0f28282328d394dd8d 1 parent 6990c3d
Harry Love authored
View
2  README.markdown
@@ -7,7 +7,7 @@
The Geokit gem provides the following:
- * Distance calculations between two points on the earth. Calculate the distance in miles or KM, with all the trigonometry abstracted away by GeoKit.
+ * Distance calculations between two points on the earth. Calculate the distance in miles, kilometers, or nautical miles, with all the trigonometry abstracted away by GeoKit.
* Geocoding from multiple providers. It currently supports Google, Yahoo, Geocoder.us, and Geocoder.ca geocoders, and it provides a uniform response structure from all of them. It also provides a fail-over mechanism, in case your input fails to geocode in one service.
* Rectangular bounds calculations: is a point within a given rectangular bounds?
* Heading and midpoint calculations
View
2  Rakefile
@@ -2,7 +2,7 @@
require 'rubygems'
require 'hoe'
-require './lib/geokit.rb'
+require './lib/geokit'
Hoe.new('Geokit', Geokit::VERSION) do |p|
# p.rubyforge_name = 'Geokitx' # if different than lowercase project name
View
41 lib/geokit/mappable.rb
@@ -9,14 +9,17 @@ module Geokit
# * Pythagorean Theory (flat Earth) - which assumes the world is flat and loses accuracy over long distances.
# * Haversine (sphere) - which is fairly accurate, but at a performance cost.
#
- # Distance units supported are :miles and :kms.
+ # Distance units supported are :miles, :kms, and :nms.
module Mappable
PI_DIV_RAD = 0.0174
KMS_PER_MILE = 1.609
+ NMS_PER_MILE = 0.868976242
EARTH_RADIUS_IN_MILES = 3963.19
EARTH_RADIUS_IN_KMS = EARTH_RADIUS_IN_MILES * KMS_PER_MILE
+ EARTH_RADIUS_IN_NMS = EARTH_RADIUS_IN_MILES * NMS_PER_MILE
MILES_PER_LATITUDE_DEGREE = 69.1
KMS_PER_LATITUDE_DEGREE = MILES_PER_LATITUDE_DEGREE * KMS_PER_MILE
+ NMS_PER_LATITUDE_DEGREE = MILES_PER_LATITUDE_DEGREE * NMS_PER_MILE
LATITUDE_DEGREES = EARTH_RADIUS_IN_MILES / MILES_PER_LATITUDE_DEGREE
# Mix below class methods into the includer.
@@ -27,7 +30,7 @@ def self.included(receiver) # :nodoc:
module ClassMethods #:nodoc:
# Returns the distance between two points. The from and to parameters are
# required to have lat and lng attributes. Valid options are:
- # :units - valid values are :miles or :kms (Geokit::default_units is the default)
+ # :units - valid values are :miles, :kms, :nms (Geokit::default_units is the default)
# :formula - valid values are :flat or :sphere (Geokit::default_formula is the default)
def distance_between(from, to, options={})
from=Geokit::LatLng.normalize(from)
@@ -67,7 +70,11 @@ def heading_between(from,to)
# will be used instead of this method.
def endpoint(start,heading, distance, options={})
units = options[:units] || Geokit::default_units
- radius = units == :miles ? EARTH_RADIUS_IN_MILES : EARTH_RADIUS_IN_KMS
+ radius = case units
+ when :kms: EARTH_RADIUS_IN_KMS
+ when :nms: EARTH_RADIUS_IN_NMS
+ else EARTH_RADIUS_IN_MILES
+ end
start=Geokit::LatLng.normalize(start)
lat=deg2rad(start.lat)
lng=deg2rad(start.lng)
@@ -86,7 +93,7 @@ def endpoint(start,heading, distance, options={})
# Returns the midpoint, given two points. Returns a LatLng.
# Typically, the instance method will be used instead of this method.
# Valid option:
- # :units - valid values are :miles or :kms (:miles is the default)
+ # :units - valid values are :miles, :kms, or :nms (:miles is the default)
def midpoint_between(from,to,options={})
from=Geokit::LatLng.normalize(from)
@@ -120,18 +127,30 @@ def to_heading(rad)
# Returns the multiplier used to obtain the correct distance units.
def units_sphere_multiplier(units)
- units == :miles ? EARTH_RADIUS_IN_MILES : EARTH_RADIUS_IN_KMS
+ case units
+ when :kms: EARTH_RADIUS_IN_KMS
+ when :nms: EARTH_RADIUS_IN_NMS
+ else EARTH_RADIUS_IN_MILES
+ end
end
# Returns the number of units per latitude degree.
def units_per_latitude_degree(units)
- units == :miles ? MILES_PER_LATITUDE_DEGREE : KMS_PER_LATITUDE_DEGREE
+ case units
+ when :kms: KMS_PER_LATITUDE_DEGREE
+ when :nms: NMS_PER_LATITUDE_DEGREE
+ else MILES_PER_LATITUDE_DEGREE
+ end
end
# Returns the number units per longitude degree.
def units_per_longitude_degree(lat, units)
miles_per_longitude_degree = (LATITUDE_DEGREES * Math.cos(lat * PI_DIV_RAD)).abs
- units == :miles ? miles_per_longitude_degree : miles_per_longitude_degree * KMS_PER_MILE
+ case units
+ when :kms: miles_per_longitude_degree * KMS_PER_MILE
+ when :nms: miles_per_longitude_degree * NMS_PER_MILE
+ else miles_per_longitude_degree
+ end
end
end
@@ -143,12 +162,12 @@ def units_per_longitude_degree(lat, units)
def to_lat_lng
return self if instance_of?(Geokit::LatLng) || instance_of?(Geokit::GeoLoc)
return LatLng.new(send(self.class.lat_column_name),send(self.class.lng_column_name)) if self.class.respond_to?(:acts_as_mappable)
- return nil
+ nil
end
# Returns the distance from another point. The other point parameter is
# required to have lat and lng attributes. Valid options are:
- # :units - valid values are :miles or :kms (:miles is the default)
+ # :units - valid values are :miles, :kms, :or :nms (:miles is the default)
# :formula - valid values are :flat or :sphere (:sphere is the default)
def distance_to(other, options={})
self.class.distance_between(self, other, options)
@@ -169,14 +188,14 @@ def heading_from(other)
# Returns the endpoint, given a heading (in degrees) and distance.
# Valid option:
- # :units - valid values are :miles or :kms (:miles is the default)
+ # :units - valid values are :miles, :kms, or :nms (:miles is the default)
def endpoint(heading,distance,options={})
self.class.endpoint(self,heading,distance,options)
end
# Returns the midpoint, given another point on the map.
# Valid option:
- # :units - valid values are :miles or :kms (:miles is the default)
+ # :units - valid values are :miles, :kms, or :nms (:miles is the default)
def midpoint_to(other, options={})
self.class.midpoint_between(self,other,options)
end
View
21 test/test_latlng.rb
@@ -24,6 +24,11 @@ def test_distance_between_same_with_kms_and_flat
assert_equal 0, @loc_a.distance_to(@loc_a, :units => :kms, :formula => :flat)
end
+ def test_distance_between_same_with_nms_and_flat
+ assert_equal 0, Geokit::LatLng.distance_between(@loc_a, @loc_a, :units => :nms, :formula => :flat)
+ assert_equal 0, @loc_a.distance_to(@loc_a, :units => :nms, :formula => :flat)
+ end
+
def test_distance_between_same_with_miles_and_sphere
assert_equal 0, Geokit::LatLng.distance_between(@loc_a, @loc_a, :units => :miles, :formula => :sphere)
assert_equal 0, @loc_a.distance_to(@loc_a, :units => :miles, :formula => :sphere)
@@ -34,6 +39,11 @@ def test_distance_between_same_with_kms_and_sphere
assert_equal 0, @loc_a.distance_to(@loc_a, :units => :kms, :formula => :sphere)
end
+ def test_distance_between_same_with_nms_and_sphere
+ assert_equal 0, Geokit::LatLng.distance_between(@loc_a, @loc_a, :units => :nms, :formula => :sphere)
+ assert_equal 0, @loc_a.distance_to(@loc_a, :units => :nms, :formula => :sphere)
+ end
+
def test_distance_between_diff_using_defaults
assert_in_delta 3.97, Geokit::LatLng.distance_between(@loc_a, @loc_e), 0.01
assert_in_delta 3.97, @loc_a.distance_to(@loc_e), 0.01
@@ -49,6 +59,11 @@ def test_distance_between_diff_with_kms_and_flat
assert_in_delta 6.39, @loc_a.distance_to(@loc_e, :units => :kms, :formula => :flat), 0.4
end
+ def test_distance_between_diff_with_nms_and_flat
+ assert_in_delta 3.334, Geokit::LatLng.distance_between(@loc_a, @loc_e, :units => :nms, :formula => :flat), 0.4
+ assert_in_delta 3.334, @loc_a.distance_to(@loc_e, :units => :nms, :formula => :flat), 0.4
+ end
+
def test_distance_between_diff_with_miles_and_sphere
assert_in_delta 3.97, Geokit::LatLng.distance_between(@loc_a, @loc_e, :units => :miles, :formula => :sphere), 0.01
assert_in_delta 3.97, @loc_a.distance_to(@loc_e, :units => :miles, :formula => :sphere), 0.01
@@ -59,12 +74,18 @@ def test_distance_between_diff_with_kms_and_sphere
assert_in_delta 6.39, @loc_a.distance_to(@loc_e, :units => :kms, :formula => :sphere), 0.01
end
+ def test_distance_between_diff_with_nms_and_sphere
+ assert_in_delta 3.454, Geokit::LatLng.distance_between(@loc_a, @loc_e, :units => :nms, :formula => :sphere), 0.01
+ assert_in_delta 3.454, @loc_a.distance_to(@loc_e, :units => :nms, :formula => :sphere), 0.01
+ end
+
def test_manually_mixed_in
assert_equal 0, Geokit::LatLng.distance_between(@point, @point)
assert_equal 0, @point.distance_to(@point)
assert_equal 0, @point.distance_to(@loc_a)
assert_in_delta 3.97, @point.distance_to(@loc_e, :units => :miles, :formula => :flat), 0.2
assert_in_delta 6.39, @point.distance_to(@loc_e, :units => :kms, :formula => :flat), 0.4
+ assert_in_delta 3.334, @point.distance_to(@loc_e, :units => :nms, :formula => :flat), 0.4
end
def test_heading_between
Please sign in to comment.
Something went wrong with that request. Please try again.