Source code for Map.utils

#    Eve W-Space
#    Copyright (C) 2013  Andrew Austin and other contributors
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version. An additional term under section
#    7 of the GPL is included in the LICENSE file.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#from Map.models import *
from collections import defaultdict
from core.models import SystemJump, Type, Location
from core.utils import get_config
from datetime import timedelta
from django.conf import settings
from django.contrib.sites.models import Site
from django.core.cache import cache
from django.db.models import Q
from math import pow, sqrt
import datetime
import json
import pytz

[docs]class MapJSONGenerator(object): """ A MapJSONGenerator is instantiated with a map and user. It provides a method that returns the JSON representation of the map. """ def __init__(self, map, user): self.map = map self.user = user self.levelY = 0 self.pvp_threshold = int(get_config("MAP_PVP_THRESHOLD", user).value) self.npc_threshold = int(get_config("MAP_NPC_THRESHOLD", user).value) self.interest_time = int(get_config("MAP_INTEREST_TIME", user).value) def _get_interest_path(self): """ Returns a list of MapSystems that are on the path to any system of interest """ try: return self._interest_path except AttributeError: threshold = datetime.datetime.now(pytz.utc)\ - timedelta(minutes=self.interest_time) systems =[] for system in self.map.systems.filter( interesttime__gt=threshold).iterator(): systems.extend(self.get_path_to_map_system(system)) self._interest_path = systems return systems @staticmethod def get_cache_key(map_inst): return '%s_map' % map_inst.pk
[docs] def get_path_to_map_system(self, system): """ Returns a list of MapSystems on the route between the map root and the provided MapSystem. """ systemlist = [] parent = system while parent: systemlist.append(parent) if parent.parentsystem and not parent.parent_wormhole.collapsed: parent = parent.parentsystem else: parent = None return systemlist
[docs] def get_system_icon(self, system): """ Takes a MapSystem and returns the appropriate icon to display on the map as a realative URL. """ pvp_threshold = self.pvp_threshold npc_threshold = self.npc_threshold staticPrefix = "%s" % (settings.STATIC_URL + "images/") if system.system.stfleets.filter(ended__isnull=True).exists(): return staticPrefix + "farm.png" if system.system.shipkills + system.system.podkills > pvp_threshold: return staticPrefix + "pvp.png" if system.system.npckills > npc_threshold: return staticPrefix + "carebears.png" return None
[docs] def system_to_dict(self, system, levelX): """ Takes a MapSystem and X,Y data and returns the dict of information to be passed to the map JS as JSON. """ interesttime = self.interest_time threshold = datetime.datetime.now(pytz.utc) - timedelta(minutes=interesttime) if system.interesttime and system.interesttime > threshold: interest = True else: interest = False path = False if system in self._get_interest_path(): path = True if system.system.is_wspace(): effect = system.system.wsystem.effect else: effect = None if system.parentsystem: parentWH = system.parent_wormhole if parentWH.collapsed: collapsed = True else: collapsed = False result = {'sysID': system.system.pk, 'Name': system.system.name, 'LevelX': levelX, 'LevelY': self.levelY, 'SysClass': system.system.sysclass, 'Friendly': system.friendlyname, 'interest': interest, 'interestpath': path, 'ParentID': system.parentsystem.pk, 'activePilots': len(system.system.pilot_list), 'WhToParent': parentWH.bottom_type.name, 'WhFromParent': parentWH.top_type.name, 'WhMassStatus': parentWH.mass_status, 'WhTimeStatus': parentWH.time_status, 'WhTotalMass': parentWH.max_mass, 'WhJumpMass': parentWH.jump_mass, 'WhToParentBubbled': parentWH.bottom_bubbled, 'WhFromParentBubbled': parentWH.top_bubbled, 'iconImageURL': self.get_system_icon(system), 'whID': parentWH.pk, 'msID': system.pk, 'backgroundImageURL': self.get_system_background(system), 'effect': effect, 'collapsed': collapsed} else: result = {'sysID': system.system.pk, 'Name': system.system.name, 'LevelX': levelX, 'LevelY': self.levelY, 'SysClass': system.system.sysclass, 'Friendly': system.friendlyname, 'interest': interest, 'activePilots': len(system.system.pilot_list), 'interestpath': path, 'ParentID': None, 'WhToParent': "", 'WhFromParent': "", 'WhTotalMass': None, 'WhJumpMass': None, 'WhMassStatus': None, 'WhTimeStatus': None, 'WhToParentBubbled': None, 'WhFromParentBubbled': None, 'iconImageURL': self.get_system_icon(system), 'whID': None, 'msID': system.pk, 'backgroundImageURL': self.get_system_background(system), 'effect': effect, 'collapsed': False} return result
[docs] def get_system_background(self, system): """ Takes a MapSystem and returns the appropriate background icon as a relative URL or None. """ staticPrefix = "%s" % (settings.STATIC_URL + "images/") if system.system.importance == 0: return None if system.system.importance == 1: return staticPrefix + "skull.png" if system.system.importance == 2: return staticPrefix + "mark.png" raise ValueError
[docs] def get_systems_json(self): """Returns a JSON string representing the systems in a map.""" cache_key = self.get_cache_key(self.map) cached = cache.get(cache_key) if cached == None: self.systems = defaultdict(list) for system in self.map.systems.all()\ .select_related('system', 'parentsystem', 'parent_womrhole')\ .iterator(): self.systems[system.parentsystem_id].append(system) root = self.systems[None][0] syslist = [self.system_to_dict(root, 0),] self.recursive_system_data_generator(root, syslist, 1) cached = syslist cache.set(cache_key, cached, 15) user_locations_dict = cache.get('user_%s_locations' % self.user.pk) if user_locations_dict: user_img = "%s/images/mylocation.png" % (settings.STATIC_URL) user_locations = [i[1][0] for i in user_locations_dict.items()] for system in cached: if system['sysID'] in user_locations and system['iconImageURL'] == None: system['iconImageURL'] = user_img return json.dumps(cached, sort_keys=True)
[docs] def recursive_system_data_generator(self, start_sys, syslist, levelX): """ Prepares a list of MapSystem objects for conversion to JSON for map JS. Takes a queryset of MapSystems and the current list of systems prepared for JSON. """ # We will need an index later, so let's enumerate the mapSystems enumSystems = enumerate(self.systems[start_sys.pk], start=0) for item in enumSystems: i = item[0] system = item[1] if i > 0: self.levelY +=1 syslist.append(self.system_to_dict(system, levelX)) self.recursive_system_data_generator(system, syslist, levelX + 1)
[docs]def get_wormhole_type(system1, system2): """Gets the one-way wormhole types between system1 and system2.""" from Map.models import WormholeType source = "K" destination = "K" # Set the source and destination for system1 > system2 if system1.sysclass < 7: source = str(system1.sysclass) if system1.sysclass == 7: source = "H" if system1.sysclass > 7: source = "NH" destination = system2.sysclass sourcewh = None if source == "H": if WormholeType.objects.filter(source="H", destination=destination).count() == 0: sourcewh = WormholeType.objects.filter(source="K", destination=destination).all() else: sourcewh = WormholeType.objects.filter(source="H", destination=destination).all() if source == "NH": if WormholeType.objects.filter(source="NH", destination=destination).count() == 0: sourcewh = WormholeType.objects.filter(source="K", destination=destination).all() else: sourcewh = WormholeType.objects.filter(source="NH", destination=destination).all() if source == "5" or source == "6": if WormholeType.objects.filter(source="Z", destination=destination).count() != 0: sourcewh = WormholeType.objects.filter( Q(source="Z") | Q(source='W')).filter( destination=destination).all() if sourcewh == None: sourcewh = WormholeType.objects.filter(Q(source=source) | Q(source='W') ).filter(destination=destination).all() return sourcewh
[docs]def get_possible_wh_types(system1, system2): """Takes two systems and gets the possible wormhole types between them. For example, given system1 as highsec and system2 as C2, it should return R943 and B274. system1 is the source and system2 is the destination. Results are returned as lists because some combinations have multiple possibilities. Returns a dict in the format {system1: [R943,], system2: [B274,]}. """ # Get System1 > System2 forward = get_wormhole_type(system1, system2) # Get Reverse reverse = get_wormhole_type(system2, system1) result = {'system1': forward, 'system2': reverse} return result
[docs]def convert_signature_id(sigid): """ Standardize the signature ID to XXX-XXX if info is available. """ escaped_sigid = sigid.replace(' ','').replace('-','').upper() if len(escaped_sigid) == 6: return "%s-%s" % (escaped_sigid[:3], escaped_sigid[3:]) else: return sigid.upper()
[docs]class RouteFinder(object): """ A RouteFinder object is created with two system objects and has methods for getting the shortest stargate jump route length, the light-year distance, and the shortest stargate route as a list of KSystem objects. """ def __init__(self): from django.core.cache import cache if not cache.get('route_graph'): self._cache_graph() else: import cPickle self.graph = cPickle.loads(cache.get('route_graph')) def _get_ly_distance(self, sys1, sys2): """ Gets the distance in light years between two systems. """ x1 = sys1.x y1 = sys1.y z1 = sys1.z x2 = sys2.x y2 = sys2.y z2 = sys2.z distance = sqrt(pow(x1 - x2 ,2) + pow(y1-y2,2) + pow(z1-z2,2)) / 9.4605284e+15 return distance def ly_distance(self, sys1, sys2): return self._get_ly_distance(sys1, sys2) def route_as_ids(self, sys1, sys2): return self._find_route(sys1, sys2) def route(self, sys1, sys2): from Map.models import KSystem return [KSystem.objects.get(pk=sysid) for sysid in self._find_route(sys1, sys2)] def route_length(self, sys1, sys2): return len(self._find_route(sys1, sys2)) def _cache_graph(self): from Map.models import KSystem from core.models import SystemJump from django.core.cache import cache import cPickle import networkx as nx if not cache.get('route_graph'): graph = nx.Graph() for from_system in KSystem.objects.all(): for to_system in SystemJump.objects.filter(fromsystem=from_system.pk): graph.add_edge(from_system.pk, to_system.tosystem) cache.set('route_graph', cPickle.dumps(graph, cPickle.HIGHEST_PROTOCOL), 0) self.graph = graph def _find_route(self, sys1, sys2): """ Takes two system objects (can be KSystem or SystemData). Returns a list of system IDs that comprise the route. """ import networkx as nx import cPickle if not self.graph: if not cache.get('route_graph'): from django.core.cache import cache self._cache_graph() self.graph = cPickle.loads(cache.get('route_graph')) else: self.graph = cPickle.loads(cache.get('route_graph')) return nx.shortest_path(self.graph, source=sys1.pk, target=sys2.pk)