From 9e5009d335256f516b61cb8742d8d9c2ef58fbb6 Mon Sep 17 00:00:00 2001 From: CMDR furrycat Date: Sat, 5 Nov 2016 11:31:45 +0000 Subject: [PATCH] Plugin to calculate headings in orbital cruise. --- plugin/heading/heading.py | 120 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 plugin/heading/heading.py diff --git a/plugin/heading/heading.py b/plugin/heading/heading.py new file mode 100644 index 0000000..d4fac92 --- /dev/null +++ b/plugin/heading/heading.py @@ -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) -- 2.7.4