class SGS::Mission
Handle a specific mission.
Attributes
Public Class Methods
Load a new mission from the missions directory.
# File lib/sgs/mission.rb, line 60 def self.load(filename) mission = new mission.read(File.open(filename)) mission end
Create the attractors and repellors as well as the track array and other items. @where is our current TrackPoint
, @current_wpt is the waypoint we're working (-1 if none), @course is the heading/speed the boat is on.
# File lib/sgs/mission.rb, line 46 def initialize @attractors = [] @repellors = [] @track = nil @current_wpt = -1 @start_time = @time = nil @where = nil @course = Course.new @distance = 0 @swing = 60 end
Public Instance Methods
On-mission means we have something to do. In other words, we have a waypoint to get to.
# File lib/sgs/mission.rb, line 164 def active? @current_wpt >= 0 and @current_wpt < @attractors.count end
Commence a mission…
# File lib/sgs/mission.rb, line 68 def commence(time = nil) @start_time = @time = time || Time.now @track = [TrackPoint.new(time, @where)] @current_wpt = 0 end
How long has the mission been active?
# File lib/sgs/mission.rb, line 170 def elapsed @time - @start_time end
Write the track data as a KML file.
xml.LineString { xml.extrude 1 xml.tessellate 1 xml.coordinates wpt.to_kml } } xml.Placemark { xml.styleUrl "#attractorLine" xml.LineString { xml.extrude 1 xml.tessellate 1 xml.coordinates wpt.to_axis_kml } }
# File lib/sgs/mission.rb, line 313 def kml_write(file) builder = Nokogiri::XML::Builder.new do |xml| xml.kml('xmlns' => 'http://www.opengis.net/kml/2.2', 'xmlns:gx' => 'http://www.google.com/kml/ext/2.2') { xml.Folder { xml_line_style(xml, "attractorLine", "0xffcf0000", 4) xml_line_style(xml, "repellorLine", "0xff00007f", 4) xml_line_style(xml, "trackLine") @attractors.each do |wpt| xml.Placemark { xml.name wpt.name xml.styleUrl "#attractorLine" xml.Point { xml.coordinates wpt.location.to_kml } } end @repellors.each do |wpt| xml.Placemark { xml.name wpt.name xml.styleUrl "#repellorLine" xml.Point { xml.coordinates wpt.location.to_kml } } end xml.Placemark { xml.name "Track" xml.styleUrl "#trackLine" xml.GX_Track { @track.each do |pt| xml.when pt.time.strftime('%Y-%m-%dT%H:%M:%S+00:00') end @track.each do |pt| xml.GX_coord pt.location.to_kml(' ') end } } } } end # Requires a hack to get rid of the 'gx:' for the when tag. file.puts builder.to_xml.gsub(/GX_/, 'gx:') end
Advance to the next waypoint. Return TRUE if there actually is one…
# File lib/sgs/mission.rb, line 205 def next_waypoint! raise "No mission currently active" unless active? @current_wpt += 1 puts "Attempting to navigate to #{waypoint.name}" if active? end
Compute the remaining distance from the current location
# File lib/sgs/mission.rb, line 230 def overall_distance start_wpt = active? ? @current_wpt : 0 dist = 0.0 loc = @where @attractors[start_wpt..-1].each do |wpt| wpt.compute_bearing(loc) dist += wpt.bearing.distance loc = wpt.location end dist end
Have we reached the waypoint? Note that even though the waypoints have a “reached” circle, we discard the last 10m on the basis that it is within the GPS
error.
# File lib/sgs/mission.rb, line 184 def reached? @distance = @attractors[@current_wpt].distance puts "ARE WE THERE YET? (dist=#{@distance})" return true if @distance <= 0.0027 # # Check to see if the next WPT is nearer than the current one #if @current_wpt < (@attractors.count - 1) # next_wpt = @attractors[@current_wpt + 1] # brng = @attractors[@current_wpt].location - next_wpt.location # angle = Bearing.absolute(waypoint.bearing.angle - next_wpt.bearing.angle) # return true if brng.distance > next_wpt.distance and # angle > (0.25 * Math::PI) and # angle < (0.75 * Math::PI) #end puts "... Sadly, no." return false end
Parse a mission file.
# File lib/sgs/mission.rb, line 244 def read(file) file.each do |line| unless line =~ /^#/ args = line.split(':') code = args[0] loc = Location.parse_str(args[1]) nrml = Bearing.dtor args[2].to_i dist = args[3].to_f name = args[4].chomp case code when /[Xx]/ @where = loc @course.wind = Bearing.new(nrml, dist) when /\d/ @attractors[code.to_i] = Waypoint.new(loc, nrml, dist, name) when /[Rr]/ @repellors << Waypoint.new(loc, nrml, dist, name, true) end end end @current_wpt = -1 end
Set new position
# File lib/sgs/mission.rb, line 145 def set_position(time, loc) @where = loc @time = time @track << TrackPoint.new(@time, @where) end
Advance the mission by a number of seconds (computing the new location in the process). Fake out the speed and thus the location.
# File lib/sgs/mission.rb, line 154 def simulated_movement(how_long = 60) puts "Advancing mission by #{how_long}s" distance = @course.speed * how_long.to_f / 3600.0 puts "Travelled #{distance * 1852.0} metres in that time." set_position(@time + how_long, @where + Bearing.new(@course.heading, distance)) end
Return the mission status as a string
# File lib/sgs/mission.rb, line 213 def status_str mins = elapsed / 60 hours = mins / 60 mins %= 60 days = hours / 24 hours %= 24 str = ">>> #{@time}, " if days < 1 str += "%dh%02dm" % [hours, mins] else str += "+%dd%%02dh%02dm" % [days, hours, mins] end str + ": My position is #{@where}" end
Terminate a mission.
# File lib/sgs/mission.rb, line 76 def terminate puts "***** Mission terminated! *****" @current_wpt = -1 end
Save the track.
# File lib/sgs/mission.rb, line 293 def track_save(filename) kml_write(File.open(filename, 'w')) end
Return the current waypoint.
# File lib/sgs/mission.rb, line 176 def waypoint active? ? @attractors[@current_wpt] : nil end
Write a mission to a file.
# File lib/sgs/mission.rb, line 269 def write(filename) File.open(filename, 'w') do |file| file.puts "#\n# My starting position." file.puts ["X", @where.to_s, @course.wind.angle_d.to_i, @course.wind.distance.to_i, "Starting position"].join(':') file.puts "#\n# Attractors." @attractors.each_with_index do |wpt, i| file.puts "%d:%s:%d:%f:%s" % [i, wpt.location, wpt.normal_d, wpt.radius, wpt.name] end file.puts "#\n# Repellors." @repellors.each do |wpt| file.puts "r:%s:%d:%f:%s" % [wpt.location, wpt.normal_d, wpt.radius, wpt.name] end end end
Do a line style. The colour is of the form aabbggrr for some unknown reason…
# File lib/sgs/mission.rb, line 361 def xml_line_style(xml, label, color = "0xffffffff", width = 1) xml.Style(:id => label) { xml.LineStyle { xml.color color xml.width width xml.GX_labelVisibility 1 } } end