-
Notifications
You must be signed in to change notification settings - Fork 0
/
geo_point.rb
135 lines (108 loc) · 3.29 KB
/
geo_point.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
require 'sugar-high/arguments'
require 'geo_calc/calc'
require 'geo_calc/extensions'
require 'geo_calc/geo_point/shared'
# Sample usage:
# p1 = GeoPoint.new(51.5136, -0.0983)
# p2 = GeoPoint.new(51.4778, -0.0015)
# dist = p1.distance_to(p2) # in km
# brng = p1.bearing_to(p2) # in degrees clockwise from north
# ... etc
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class GeoPoint
include GeoCalc::Calc::All
autoload :Shared, 'geo_calc/geo_point/shared'
autoload :ClassMethods, 'geo_calc/geo_point/class_methods'
autoload :CoreExtension, 'geo_calc/geo_point/core_extension'
attr_reader :lat, :lon
# Creates a point on the earth's surface at the supplied latitude / longitude
#
# - Numeric latitude in numeric degrees
# - Numeric longitude in numeric degrees
# Optional options
# - :radius - earth radius in km
# - :mode - coordinates mode, either :lng_lat or :lat_lng, otherwise uses global setting as per GeoPoint.coord_mode
def initialize *args
options = args.is_a?(GeoPoint) ? {} : args.last_option
earth_radius_km = options[:radius]
coord_mode = options[:mode]
case args.size
when 1
create_from_one args
when 2
create_from_two *args
else
raise "GeoPoint must be initialized with either one or to arguments defining the (latitude, longitude) coordinate on the map"
end
end
extend ClassMethods
include Shared
def coord_mode
@coord_mode ||= GeoPoint.coord_mode
end
def earth_radius_km
@earth_radius_km ||= GeoPoint.earth_radius_km # default
end
def lat= value
@lat = value.to_lat
end
def lon= value
@lon = value.to_lng
end
(Symbol.lng_symbols - [:lon]).each do |sym|
class_eval %{
alias_method :#{sym}, :lon
alias_method :#{sym}=, :lon=
}
end
alias_method :to_lng, :lng
(Symbol.lat_symbols - [:lat]).each do |sym|
class_eval %{
alias_method :#{sym}, :lat
alias_method :#{sym}=, :lat=
}
end
alias_method :to_lat, :lat
def [] key
case key
when Fixnum
raise ArgumentError, "Index must be 0 or 1" if !(0..1).cover?(key)
to_a[key]
when String, Symbol
send(key) if respond_to? key
else
raise ArgumentError, "Key must be a Fixnum (index) or a method name"
end
end
alias_method :to_dms, :to_s
def reverse_point!
self.lat = lat * -1
self.lng = lng * -1
self
end
def reverse_point
self.dup.reverse_point!
end
def to_lat_lng
[lat, lng]
end
def to_lng_lat
[lng, lat]
end
def to_a
send(:"to_#{coord_mode}")
end
protected
include ::GeoCalc::NumericCheckExt
def to_coords points
points.send(:"to_#{coord_mode}")
end
def create_from_one args
args = args.first
create_from_two *to_coords(args)
end
def create_from_two lat, lon
@lat = lat.to_lat
@lon = lon.to_lng
end
end