Class: SGS::Location

Inherits:
Object
  • Object
show all
Defined in:
lib/sgs/location.rb

Overview

Class for dealing with latitude/longitude. Includes methods for parsing, converting to a printable string, and so forth.

Note that for convenience, we retain latitude and longitude in Radians rather than degrees.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(lat = nil, long = nil) ⇒ Location

Create the Location instance. Latitude and longitude passed in radians.



60
61
62
63
# File 'lib/sgs/location.rb', line 60

def initialize(lat = nil, long = nil)
  @latitude = lat.to_f if lat
  @longitude = long.to_f if long
end

Instance Attribute Details

#latitudeObject

Returns the value of attribute latitude.



56
57
58
# File 'lib/sgs/location.rb', line 56

def latitude
  @latitude
end

#longitudeObject

Returns the value of attribute longitude.



56
57
58
# File 'lib/sgs/location.rb', line 56

def longitude
  @longitude
end

Class Method Details

.parse(data) ⇒ Object

Create a new location from a lat/long hash. Uses the instance method to parse.



108
109
110
111
112
# File 'lib/sgs/location.rb', line 108

def self.parse(data)
  loc = new
  loc.parse(data)
  loc
end

Instance Method Details

#+(bearing) ⇒ Object

Calculate a new position from the current position given a bearing (angle and distance)

This code was derived from formulae on the Movable Type site: www.movable-type.co.uk/scripts/latlong.html

var lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) +

Math.cos(lat1)*Math.sin(d/R)*Math.cos(angle) );

var lon2 = lon1 + Math.atan2(Math.sin(angle)*Math.sin(d/R)*Math.cos(lat1),

Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));


82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/sgs/location.rb', line 82

def +(bearing)
  loc = Location.new
  sin_angle = Math.sin(bearing.angle)
  cos_angle = Math.cos(bearing.angle)
  sin_dstr = Math.sin(bearing.distance / EARTH_RADIUS)
  cos_dstr = Math.cos(bearing.distance / EARTH_RADIUS)
  sin_lat1 = Math.sin(@latitude)
  cos_lat1 = Math.cos(@latitude)
  loc.latitude = Math.asin(sin_lat1*cos_dstr + cos_lat1*sin_dstr*cos_angle)
  sin_lat2 = Math.sin(@latitude)
  loc.longitude = @longitude + Math.atan2(sin_angle*sin_dstr*cos_lat1,
                                          cos_dstr - sin_lat1*sin_lat2)
  loc
end

#-(loc) ⇒ Object

Subtract one location from another, returning a bearing



67
68
69
# File 'lib/sgs/location.rb', line 67

def -(loc)
  Bearing.compute(self, loc)
end

#latitude_array(fmt = nil) ⇒ Object

Produce a latitude array for NMEA output.



195
196
197
# File 'lib/sgs/location.rb', line 195

def latitude_array(fmt = nil)
  _make_ll_array latitude_d, "NS", fmt
end

#latitude_dObject

Return the latitude in degrees.



183
184
185
# File 'lib/sgs/location.rb', line 183

def latitude_d
  Bearing.rtod @latitude
end

#latitude_d=(val) ⇒ Object

Set the latitude using a value in degrees.



189
190
191
# File 'lib/sgs/location.rb', line 189

def latitude_d=(val)
  @latitude = Bearing.dtor val
end

#longitude_array(fmt = nil) ⇒ Object

Produce a longitude array for NMEA output.



213
214
215
# File 'lib/sgs/location.rb', line 213

def longitude_array(fmt = nil)
  _make_ll_array longitude_d, "EW", fmt
end

#longitude_dObject

Return the longitude in degrees.



201
202
203
# File 'lib/sgs/location.rb', line 201

def longitude_d
  Bearing.rtod @longitude
end

#longitude_d=(val) ⇒ Object

Set the longitude using a value in degrees.



207
208
209
# File 'lib/sgs/location.rb', line 207

def longitude_d=(val)
  @longitude = Bearing.dtor val
end

#move!(bearing) ⇒ Object

Move to the new location



99
100
101
102
103
# File 'lib/sgs/location.rb', line 99

def move!(bearing)
  loc = calculate(bearing)
  self.latitude = loc.latitude
  self.longitude = loc.longitude
end

#parse(data) ⇒ Object

Parse the lat/long values passed as a string. This function should be able to handle any type of lat/long string, in most general formats. See :to_s for examples.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/sgs/location.rb', line 118

def parse(data)
  llvals = data.split /,/
  if llvals.count == 1
    #
    # Must be space-separated. Try that...
    llvals = data.split(/ /)
    if llvals.count != 2
      raise ArgumentError.new "Cannot split lat/long values"
    end
  elsif llvals.count != 2
    #
    # Too many comma separators.
    raise ArgumentError.new "Invalid lat/long values"
  end
  self.latitude_d = _ll_parse(llvals[0], "NS")
  self.longitude_d = _ll_parse(llvals[1], "EW")
  true
end

#parse_hash(data = {}) ⇒ Object

Parse the lat/long from a hash object.



139
140
141
142
# File 'lib/sgs/location.rb', line 139

def parse_hash(data = {})
  self.latitude_d = _ll_parse(data["latitude"], "NS")
  self.longitude_d = _ll_parse(data["longitude"], "EW")
end

#to_hashObject

Convert the lat/long to a hash.



152
153
154
# File 'lib/sgs/location.rb', line 152

def to_hash
  {"latitude" => latitude_d.round(6), "longitude" => longitude_d.round(6)}
end

#to_kml(sep = ',') ⇒ Object

Display the lat/long as it would appear in a KML file.



175
176
177
178
179
# File 'lib/sgs/location.rb', line 175

def to_kml(sep = ',')
  vals = [@longitude, @latitude, 0.0]
  str_vals = vals.map {|val| "%.8f" % Bearing.rtod(val)}
  str_vals.join(sep)
end

#to_s(opts = {}) ⇒ Object

Display the lat/long as a useful string (in degrees). Output  formats are as follows (default is :d): :d “48.104051, -7.282614” :dd “48.104051N, 7.282614W” :dmm “48 6.243060N, 7 16.956840W” :dms “48 6 14.583600N, 7 16 57.410400W”



163
164
165
166
167
168
169
170
171
# File 'lib/sgs/location.rb', line 163

def to_s(opts = {})
  if valid?
    lat_str = _ll_conv(latitude_d.round(6), "NS", opts)
    lon_str = _ll_conv(longitude_d.round(6), "EW", opts)
    "#{lat_str}, #{lon_str}"
  else
    "unknown"
  end
end

#valid?Boolean

Is this location valid?

Returns:

  • (Boolean)


146
147
148
# File 'lib/sgs/location.rb', line 146

def valid?
  @latitude and @longitude
end