Module: Geokit::Mappable::ClassMethods
- Defined in:
- lib/geokit/mappable.rb
Overview
:nodoc:
Constant Summary collapse
- PI_DIV_RAD =
Math::PI / 180
- EARTH_RADIUS_IN_METERS =
6_376_772.71
- METERS_PER_LATITUDE_DEGREE =
111_181.9
- EARTH_RADIUS =
{}
- PER_LATITUDE_DEGREE =
{}
Class Method Summary collapse
Instance Method Summary collapse
-
#decimal_to_dms(deg) ⇒ Object
Given a decimal degree like -87.660333 return a 3-element array like [ -87, 39, 37.198… ].
- #deg2rad(degrees) ⇒ Object
-
#distance_between(from, to, options = {}) ⇒ Object
Returns the distance between two points.
- #distance_between_flat(from, to, units) ⇒ Object
- #distance_between_sphere(from, to, units) ⇒ Object
-
#endpoint(start, heading, distance, options = {}) ⇒ Object
Given a start point, distance, and heading (in degrees), provides an endpoint.
-
#geocode(location, options = {}) ⇒ Object
Geocodes a location using the multi geocoder.
-
#get_units!(options = {}) ⇒ Object
Extracts units from options.
-
#heading_between(from, to) ⇒ Object
Returns heading in degrees (0 is north, 90 is east, 180 is south, etc) from the first point to the second point.
-
#math_error_classes ⇒ Object
Ruby 1.9 raises Math::DomainError, but it is not defined in Ruby 1.8.
-
#midpoint_between(from, to, options = {}) ⇒ Object
Returns the midpoint, given two points.
- #rad2deg(rad) ⇒ Object
- #to_heading(rad) ⇒ Object
-
#units_per_latitude_degree(units) ⇒ Object
Returns the number of units per latitude degree.
-
#units_per_longitude_degree(lat, units) ⇒ Object
Returns the number units per longitude degree.
-
#units_sphere_multiplier(units) ⇒ Object
Returns the multiplier used to obtain the correct distance units.
Class Method Details
.register_unit(key, in_meters) ⇒ Object
163 164 165 166 |
# File 'lib/geokit/mappable.rb', line 163 def self.register_unit(key, in_meters) EARTH_RADIUS[key] = EARTH_RADIUS_IN_METERS * in_meters PER_LATITUDE_DEGREE[key] = METERS_PER_LATITUDE_DEGREE * in_meters end |
Instance Method Details
#decimal_to_dms(deg) ⇒ Object
Given a decimal degree like -87.660333 return a 3-element array like [ -87, 39, 37.198… ]
140 141 142 143 144 145 146 147 148 149 |
# File 'lib/geokit/mappable.rb', line 140 def decimal_to_dms(deg) return false unless deg.is_a?(Numeric) # seconds is 0...3599.999, representing the entire fractional part. seconds = (deg.abs % 1.0) * 3600.0 [ deg.to_i, # degrees as positive or negative integer (seconds / 60).to_i, # minutes as positive integer (seconds % 60) # seconds as positive float ] end |
#deg2rad(degrees) ⇒ Object
151 152 153 |
# File 'lib/geokit/mappable.rb', line 151 def deg2rad(degrees) degrees.to_f / 180.0 * Math::PI end |
#distance_between(from, to, options = {}) ⇒ Object
Returns the distance between two points.
42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/geokit/mappable.rb', line 42 def distance_between(from, to, = {}) units = get_units!() from = Geokit::LatLng.normalize(from) to = Geokit::LatLng.normalize(to) return 0.0 if from == to # fixes a "zero-distance" bug formula = [:formula] || Geokit.default_formula case formula when :sphere then distance_between_sphere(from, to, units) when :flat then distance_between_flat(from, to, units) end end |
#distance_between_flat(from, to, units) ⇒ Object
64 65 66 67 68 69 |
# File 'lib/geokit/mappable.rb', line 64 def distance_between_flat(from, to, units) lat_length = units_per_latitude_degree(units) * (from.lat - to.lat) lng_length = units_per_longitude_degree(from.lat, units) * (from.lng - to.lng) Math.sqrt(lat_length**2 + lng_length**2) end |
#distance_between_sphere(from, to, units) ⇒ Object
55 56 57 58 59 60 61 62 |
# File 'lib/geokit/mappable.rb', line 55 def distance_between_sphere(from, to, units) lat_sin = Math.sin(deg2rad(from.lat)) * Math.sin(deg2rad(to.lat)) lat_cos = Math.cos(deg2rad(from.lat)) * Math.cos(deg2rad(to.lat)) lng_cos = Math.cos(deg2rad(to.lng) - deg2rad(from.lng)) units_sphere_multiplier(units) * Math.acos(lat_sin + lat_cos * lng_cos) rescue *math_error_classes 0.0 end |
#endpoint(start, heading, distance, options = {}) ⇒ Object
Given a start point, distance, and heading (in degrees), provides an endpoint. Returns a LatLng instance. Typically, the instance method will be used instead of this method.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/geokit/mappable.rb', line 96 def endpoint(start, heading, distance, = {}) units = get_units!() ratio = distance.to_f / units_sphere_multiplier(units) start = Geokit::LatLng.normalize(start) lat = deg2rad(start.lat) lng = deg2rad(start.lng) heading = deg2rad(heading) sin_ratio = Math.sin(ratio) cos_ratio = Math.cos(ratio) sin_lat = Math.sin(lat) cos_lat = Math.cos(lat) end_lat = Math.asin(sin_lat * cos_ratio + cos_lat * sin_ratio * Math.cos(heading)) end_lng = lng + Math.atan2(Math.sin(heading) * sin_ratio * cos_lat, cos_ratio - sin_lat * Math.sin(end_lat)) LatLng.new(rad2deg(end_lat), rad2deg(end_lng)) end |
#geocode(location, options = {}) ⇒ Object
Geocodes a location using the multi geocoder.
132 133 134 135 136 |
# File 'lib/geokit/mappable.rb', line 132 def geocode(location, = {}) res = Geocoders::MultiGeocoder.geocode(location, ) return res if res.success? raise Geokit::Geocoders::GeocodeError end |
#get_units!(options = {}) ⇒ Object
Extracts units from options. Returns Geokit::default_units when not present. Raise an exception when given unsupported unit of length
192 193 194 195 196 197 198 |
# File 'lib/geokit/mappable.rb', line 192 def get_units!( = {}) units = [:units] units = Geokit.default_units if units.nil? [:miles, :kms, :meters, :nms].include?(units) or raise ArgumentError, "#{units} is an unsupported unit of length." units end |
#heading_between(from, to) ⇒ Object
Returns heading in degrees (0 is north, 90 is east, 180 is south, etc) from the first point to the second point. Typicaly, the instance methods will be used instead of this method.
80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/geokit/mappable.rb', line 80 def heading_between(from, to) from = Geokit::LatLng.normalize(from) to = Geokit::LatLng.normalize(to) d_lng = deg2rad(to.lng - from.lng) from_lat = deg2rad(from.lat) to_lat = deg2rad(to.lat) y = Math.sin(d_lng) * Math.cos(to_lat) x = Math.cos(from_lat) * Math.sin(to_lat) - Math.sin(from_lat) * Math.cos(to_lat) * Math.cos(d_lng) to_heading(Math.atan2(y, x)) end |
#math_error_classes ⇒ Object
Ruby 1.9 raises Math::DomainError, but it is not defined in Ruby 1.8
72 73 74 75 |
# File 'lib/geokit/mappable.rb', line 72 def math_error_classes return [Errno::EDOM, Math::DomainError] if defined?(Math::DomainError) [Errno::EDOM] end |
#midpoint_between(from, to, options = {}) ⇒ Object
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, :kms, or :nms
(:miles is the default)
123 124 125 126 127 128 129 |
# File 'lib/geokit/mappable.rb', line 123 def midpoint_between(from, to, = {}) from = Geokit::LatLng.normalize(from) heading = from.heading_to(to) distance = from.distance_to(to, ) from.endpoint(heading, distance / 2, ) end |
#rad2deg(rad) ⇒ Object
155 156 157 |
# File 'lib/geokit/mappable.rb', line 155 def rad2deg(rad) rad.to_f * 180.0 / Math::PI end |
#to_heading(rad) ⇒ Object
159 160 161 |
# File 'lib/geokit/mappable.rb', line 159 def to_heading(rad) (rad2deg(rad) + 360) % 360 end |
#units_per_latitude_degree(units) ⇒ Object
Returns the number of units per latitude degree.
181 182 183 |
# File 'lib/geokit/mappable.rb', line 181 def units_per_latitude_degree(units) PER_LATITUDE_DEGREE[units] end |
#units_per_longitude_degree(lat, units) ⇒ Object
Returns the number units per longitude degree.
186 187 188 |
# File 'lib/geokit/mappable.rb', line 186 def units_per_longitude_degree(lat, units) units_sphere_multiplier(units) * Math.cos(lat * PI_DIV_RAD) * PI_DIV_RAD end |
#units_sphere_multiplier(units) ⇒ Object
Returns the multiplier used to obtain the correct distance units. TODO: make more accurate by coping msi.nga.mil/MSISiteContent/StaticFiles/Calculators/degree.html
176 177 178 |
# File 'lib/geokit/mappable.rb', line 176 def units_sphere_multiplier(units) EARTH_RADIUS[units] end |