class SGS::Location

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.

Attributes

latitude[RW]
longitude[RW]

Public Class Methods

new(lat = nil, long = nil) click to toggle source

Create the Location instance.

# File lib/sgs/location.rb, line 53
def initialize(lat = nil, long = nil)
  @latitude = lat.to_f if lat
  @longitude = long.to_f if long
end
parse(latstr, longstr) click to toggle source

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

# File lib/sgs/location.rb, line 111
def self.parse(latstr, longstr)
  loc = new
  loc.parse(latstr, longstr)
  loc
end
parse_str(str) click to toggle source

Create a new location from a string. Uses the instance method to parse.

# File lib/sgs/location.rb, line 102
def self.parse_str(str)
  loc = new
  loc.parse_str(str)
  loc
end

Public Instance Methods

+(bearing) click to toggle source

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));
# File lib/sgs/location.rb, line 76
def +(bearing)
  loc = Location.new
  sin_angle = Math.sin(bearing.angle)
  cos_angle = Math.cos(bearing.angle)
  sin_dstr = Math.sin(bearing.distance / SGS::EARTH_RADIUS)
  cos_dstr = Math.cos(bearing.distance / SGS::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) click to toggle source

The difference between two locations is a Bearing

# File lib/sgs/location.rb, line 60
def -(loc)
  puts "Distance from #{self} to #{loc}"
  Bearing.compute(self, loc)
end
latitude_array(fmt = nil) click to toggle source
# File lib/sgs/location.rb, line 165
def latitude_array(fmt = nil)
  make_ll_array latitude_d, "NS", fmt
end
latitude_d() click to toggle source

Helper functions for working in degrees.

# File lib/sgs/location.rb, line 157
def latitude_d
  Bearing.rtod @latitude
end
latitude_d=(val) click to toggle source
# File lib/sgs/location.rb, line 161
def latitude_d=(val)
  @latitude = Bearing.dtor val
end
longitude_array(fmt = nil) click to toggle source
# File lib/sgs/location.rb, line 177
def longitude_array(fmt = nil)
  make_ll_array longitude_d, "EW", fmt
end
longitude_d() click to toggle source
# File lib/sgs/location.rb, line 169
def longitude_d
  Bearing.rtod @longitude
end
longitude_d=(val) click to toggle source
# File lib/sgs/location.rb, line 173
def longitude_d=(val)
  @longitude = Bearing.dtor val
end
move!(bearing) click to toggle source

Move to the new location

# File lib/sgs/location.rb, line 93
def move!(bearing)
  loc = calculate(bearing)
  self.latitude = loc.latitude
  self.longitude = loc.longitude
end
parse(latstr, longstr) click to toggle source

Parse a lat/long value pair (in degrees)

# File lib/sgs/location.rb, line 126
def parse(latstr, longstr)
  @latitude = ll_parse(latstr.split, "NS")
  @longitude = ll_parse(longstr.split, "EW")
end
parse_str(str) click to toggle source

Parse a lat/long value (in degrees)

# File lib/sgs/location.rb, line 119
def parse_str(str)
  latstr, longstr = str.split(',')
  parse(latstr, longstr)
end
to_kml(sep = ',') click to toggle source

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

# File lib/sgs/location.rb, line 149
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() click to toggle source

Display the lat/long as a useful string (in degrees).

# File lib/sgs/location.rb, line 139
def to_s
  if valid?
    "%s, %s" % [ll_to_s(@latitude, "NS"), ll_to_s(@longitude, "EW")]
  else
    "unknown"
  end
end
valid?() click to toggle source

Is this location valid?

# File lib/sgs/location.rb, line 133
def valid?
  @latitude and @longitude
end

Private Instance Methods

ll_parse(args, nsew) click to toggle source

Parse a string into a lat or long.

# File lib/sgs/location.rb, line 190
def ll_parse(args, nsew)
  dir = args[-1].gsub(/[\d\. ]+/, '').upcase
  args.map! {|val| val.to_f}
  val = args.shift
  val = val + args.shift / 60.0 if args.length > 0
  val = val + args.shift / 3600.0 if args.length > 0
  Bearing.dtor val * ((nsew.index(dir) == 1) ? -1 : 1)
end
ll_to_s(val, str) click to toggle source
# File lib/sgs/location.rb, line 201
def ll_to_s(val, str)
  if val < 0.0
    chr = str[1]
    val = -val
  else
    chr = str[0]
  end
  "%8.6f%c" % [Bearing.rtod(val), chr]
end
make_ll_array(val, nsew, fmt = nil) click to toggle source

Create a Lat/Long array suitable for an NMEA output

# File lib/sgs/location.rb, line 213
def make_ll_array(val, nsew, fmt = nil)
  fmt ||= "%02d%07.4f"
  if (val < 0)
    val = -val
    ne = nsew[1]
  else
    ne = nsew[0]
  end
  deg = val.to_i
  val = (val - deg) * 60
  [fmt % [deg, val], ne.chr]
end