# frozen_string_literal: true =begin /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* Latitude/longitude spherical geodesy tools (c) Chris Veness 2002-2016 */ /* MIT Licence */ /* www.movable-type.co.uk/scripts/latlong.html */ /* www.movable-type.co.uk/scripts/geodesy/docs/module-latlon-spherical.html */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ Código portado de biblioteca LatLon do JS =end class Map::LatLonService attr_reader :lat, :lon def initialize(lat_or_coordinate, lon = nil) if lon @lat = lat_or_coordinate.to_f @lon = lon.to_f elsif lat_or_coordinate.is_a?(Array) @lat = lat_or_coordinate.first.to_f @lon = lat_or_coordinate.second.to_f elsif lat_or_coordinate.is_a?(Hash) lat = HashWithIndifferentAccess.new(lat_or_coordinate) @lat = lat[:latitude].to_f @lon = lat[:longitude].to_f else raise 'Parâmetros inválidos' end Float.include Map::Float end def bearing_to(point) raise 'Point não é do tipo LatLon' unless point.is_a?(Map::LatLonService) _φ1 = self.lat.to_radians _φ2 = point.lat.to_radians _Δλ = (point.lon - self.lon).to_radians y = Math.sin(_Δλ) * Math.cos(_φ2) x = Math.cos(_φ1) * Math.sin(_φ2) - Math.sin(_φ1) * Math.cos(_φ2) * Math.cos(_Δλ) θ = Math.atan2(y, x) (θ.to_degrees + 360) % 360 end def destination_point(distance, bearing) radius = 6371e3 # _φ2 = asin( sin_φ1⋅cosδ + cos_φ1⋅sinδ⋅cosθ ) # _λ2 = _λ1 + atan2( sinθ⋅sinδ⋅cos_φ1, cosδ − sin_φ1⋅sin_φ2 ) # see http://williams.best.vwh.net/avform.htm#LL δ = distance / radius θ = bearing.to_f.to_radians _φ1 = self.lat.to_radians _λ1 = self.lon.to_radians _φ2 = Math.asin(Math.sin(_φ1)*Math.cos(δ) + Math.cos(_φ1)*Math.sin(δ)*Math.cos(θ)) x = Math.cos(δ) - Math.sin(_φ1) * Math.sin(_φ2) y = Math.sin(θ) * Math.sin(δ) * Math.cos(_φ1) _λ2 = _λ1 + Math.atan2(y, x) self.class.new(_φ2.to_degrees, (_λ2.to_degrees + 540) % 360-180) end def distance_to(point) radius = 6371e3 _φ1 = self.lat.to_radians _λ1 = self.lon.to_radians _φ2 = point.lat.to_radians _λ2 = point.lon.to_radians _Δφ = _φ2 - _φ1 _Δλ = _λ2 - _λ1 a = Math.sin(_Δφ/2) * Math.sin(_Δφ/2) + Math.cos(_φ1) * Math.cos(_φ2) * Math.sin(_Δλ/2) * Math.sin(_Δλ/2) c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)) radius * c end def to_hash { latitude: self.lat, longitude: self.lon } end end