Plugin to calculate headings in orbital cruise.
authorCMDR furrycat <elite@furrycat.net>
Sat, 5 Nov 2016 11:31:45 +0000 (11:31 +0000)
committerCMDR furrycat <elite@furrycat.net>
Sat, 5 Nov 2016 11:33:14 +0000 (11:33 +0000)
plugin/heading/heading.py [new file with mode: 0644]

diff --git a/plugin/heading/heading.py b/plugin/heading/heading.py
new file mode 100644 (file)
index 0000000..d4fac92
--- /dev/null
@@ -0,0 +1,120 @@
+import asyncio
+import math
+import re
+import shlex
+
+from plugins import PluginCommand
+import bot
+import cat
+
+class Heading(object):
+  def description(self):
+    return 'Helper for planetary navigation.'
+
+  def valid_commands(self):
+    return ['heading']
+
+  @asyncio.coroutine
+  def handle_command(self, message, command, raw):
+    if command not in self.valid_commands():
+      return PluginCommand.ignored
+    yield from self.handle_heading(message, shlex.split(raw)[1:])
+    return PluginCommand.exclusive
+
+  @asyncio.coroutine
+  def handle_help(self, message, command, *args):
+    yield from self.help_heading(message, *args)
+
+  @asyncio.coroutine
+  def handle_heading(self, message, args):
+    if not len(args):
+      return
+
+    command = args[0].lower()
+    if command == 'help':
+      yield from self.help_heading(message)
+    elif command in ['from', 'to']:
+      yield from self.navigate(message, args)
+
+  @asyncio.coroutine
+  def help_heading(self, message, *args):
+    lines = [
+      '{} can assist you with orbital cruise.'.format(client.user.mention),
+      '',
+      'The two numbers at the right of the HUD are the **latitude**, measured from *-90*  (south) to *90*  (north) and below it the **longitude**, measured from *-180*  (west) to *180*  (east).',
+      '',
+      'Top number **latitude**.  Bottom number **longitude**.',
+      '',
+      'To increase your  *latitude*  fly at heading **0**.  To decrease your  *latitude*  fly at heading **180**.',
+      'To increase your  *longitude*  fly at heading **90**.  To decrease your  *longitude*  fly at heading **270**.',
+      'To  *increase both*  your latitude and longitude fly at **45**.  To  *decrease both*  your latitude and longitude fly at **225**.',
+      'To  *increase*  your  *latitude*  and  *decrease*  your  *longitude*  fly at **315**.  To  *decrease*  your  *latitude*  and  *increase*  your  *longitude*  fly at **135**.',
+      '',
+      'Remember that co-ordinates can be negative and positive.  To go from lat. -78 to lat. -27, for instance, requires an *increase* hence a heading of **0**.',
+      '',
+      'I can calculate the exact heading to fly between your current position and target co-ordinates.  Send me a command like this:',
+      '```heading from 44.08 -33.12 to -27.14 -130.95```'
+    ]
+    yield from bot.say_many(message.channel, lines)
+
+  @asyncio.coroutine
+  def navigate(self, message, args):
+    log.debug('Parsing {}'.format(args))
+
+    parsed = {}
+    ok = False
+    i = 0
+    while i < len(args):
+      arg = args[i].lower()
+      if i > len(args) - 1:
+        break
+      try:
+        param1 = args[i + 1]
+        param2 = args[i + 2]
+      except IndexError:
+        break
+      log.info('{}: {}={} {}'.format(i, arg, param1, param2))
+
+      if arg in ['from', 'to']:
+        k = arg
+        try:
+          params = [float(re.sub(r'[^\d.-]', '', param)) for param in [param1, param2]]
+          parsed[k] = params
+          ok = True
+          i += 1
+        except ValueError:
+          break
+      else:
+        yield from bot.say(message.channel, 'What is {}?'.format(arg))
+        return
+
+      if ok:
+        i += 2
+      else:
+        break
+
+    if not ok:
+      log.info('Failed to parse heading.  Got: {}'.format(parsed))
+      yield from bot.say(message.channel, '{}?'.format(arg))
+      return None
+
+    for k in ['from', 'to']:
+      latitude, longitude = parsed[k]
+      if latitude < -90 or latitude > 90:
+        yield from bot.say(message.channel, 'Invalid latitude!')
+        return
+      if longitude < -180 or longitude > 180:
+        yield from bot.say(message.channel, 'Invalid longitude!')
+        return
+
+    yield from bot.say(message.channel, self.calculate_bearing(parsed['from'], parsed['to']))
+
+  def calculate_bearing(self, start, end):
+    log.info('Calculating bearing from {} to {}.'.format(start, end))
+
+    slat, slong = [math.radians(l) for l in start]
+    elat, elong = [math.radians(l) for l in end]
+
+    x = (math.cos(slat) * math.sin(elat)) - (math.sin(slat) * math.cos(elat) * math.cos(elong - slong));
+    y = math.sin(elong - slong) * math.cos(elat)
+    return int(math.degrees(math.atan2(x, y)) % 360)