Module: Geokit::Mappable::ClassMethods

Defined in:
lib/geokit/mappable.rb

:nodoc:

Constant Summary collapse

`Math::PI / 180`
`6_376_772.71`
METERS_PER_LATITUDE_DEGREE =
`111_181.9`
`{}`
PER_LATITUDE_DEGREE =
`{}`

Instance Method Summary collapse

• Given a decimal degree like -87.660333 return a 3-element array like [ -87, 39, 37.198… ].

• Returns the distance between two points.

• Given a start point, distance, and heading (in degrees), provides an endpoint.

• Geocodes a location using the multi geocoder.

• Extracts units from options.

• Returns heading in degrees (0 is north, 90 is east, 180 is south, etc) from the first point to the second point.

• Ruby 1.9 raises Math::DomainError, but it is not defined in Ruby 1.8.

• Returns the midpoint, given two points.

• Returns the number of units per latitude degree.

• Returns the number units per longitude degree.

• 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```

 ``` 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.

Examples:

``Geokit::GeoLoc.distance_between("43.8374249,4.3600687", "44.1253665,4.0852818")``

Parameters:

• from (String, Array, LatLng)

`required` - `Geokit::LatLng` compatible value

• to (String, Array, LatLng)

`required` - `Geokit::LatLng` compatible value

• options (Hash) (defaults to: {})

a customizable set of options

Options Hash (options):

• :units (String, Symbol)

valid values are :miles, :kms, :nms. Default to Geokit::default_units

• :formula (String, Symbol)

valid values are :flat or :sphere. Default to Geokit::default_formula

 ``` 42 43 44 45 46 47 48 49 50 51 52 53``` ```# File 'lib/geokit/mappable.rb', line 42 def distance_between(from, to, options = {}) units = get_units!(options) from = Geokit::LatLng.normalize(from) to = Geokit::LatLng.normalize(to) return 0.0 if from == to # fixes a "zero-distance" bug formula = options[: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, options = {}) units = get_units!(options) 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.

Raises:

 ``` 132 133 134 135 136``` ```# File 'lib/geokit/mappable.rb', line 132 def geocode(location, options = {}) res = Geocoders::MultiGeocoder.geocode(location, options) 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!(options = {}) units = options[: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```

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, options = {}) from = Geokit::LatLng.normalize(from) heading = from.heading_to(to) distance = from.distance_to(to, options) from.endpoint(heading, distance / 2, options) end```

 ``` 155 156 157``` ```# File 'lib/geokit/mappable.rb', line 155 def rad2deg(rad) rad.to_f * 180.0 / Math::PI end```

 ``` 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```