#!/usr/bin/env python #**************************************************************************** # mapdata.py, provides non-GUI base classes for mapping data # # FlyWay, a VFR/IFR Route Planner for Pilots # Copyright (C) 2002, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, Version 2. This program is # distributed in the hope that it will be useful, but WITTHOUT ANY WARRANTY. #***************************************************************************** from waypoint import Waypoint, Airport, Navaid, Fixpoint from route import RouteLeg from units import Angle import math class MapData: """Calculates and stores mapping info""" marginFactor = 1.1 mapPixels = 500 minMapSize = 20 def __init__(self, route): self.route = route self.routeList = [] self.airportList = [] self.navaidList = [] self.fixList = [] self.maxLat = 0.0 self.minLat = 0.0 self.maxLng = 0.0 self.minLng = 0.0 self.calcBounds() self.addRouteWp() def calcBounds(self): """Determine map boundaries for a square map""" if self.route.wpList: self.maxLat = max([wp.latitudeValue() for wp in self.route.wpList]) self.minLat = min([wp.latitudeValue() for wp in self.route.wpList]) self.maxLng = max([abs(wp.longitudeValue()) for wp \ in self.route.wpList]) self.minLng = min([abs(wp.longitudeValue()) for wp \ in self.route.wpList]) lngFactor = (math.cos(self.minLat * math.pi/180) \ + math.cos(self.maxLat * math.pi/180)) / 2.0 xSize = (self.maxLng - self.minLng) * RouteLeg.nmLng * lngFactor ySize = (self.maxLat - self.minLat) * RouteLeg.nmLat if xSize == 0 and ySize == 0: self.maxLat += MapData.minMapSize / (2 * RouteLeg.nmLat) self.minLat -= MapData.minMapSize / (2 * RouteLeg.nmLat) self.maxLng += MapData.minMapSize \ / (2 * RouteLeg.nmLng * lngFactor) self.minLng -= MapData.minMapSize \ / (2 * RouteLeg.nmLng * lngFactor) elif xSize > ySize: # expand short side to make map square delta = (xSize - ySize) / (2 * RouteLeg.nmLat) self.maxLat += delta self.minLat -= delta else: delta = (ySize - xSize) / (2 * RouteLeg.nmLng * lngFactor) self.maxLng += delta self.minLng -= delta self.expandBounds(MapData.marginFactor) def expandBounds(self, factor): """Enlarge boundary by factor on each side""" latDelta = (self.maxLat - self.minLat) * (factor - 1) self.maxLat += latDelta self.minLat -= latDelta lngDelta = (self.maxLng - self.minLng) * (factor - 1) self.maxLng += lngDelta self.minLng -= lngDelta def addRouteWp(self): """Add waypoints from the route to the map list""" self.routeList = [MapItem(wp, self) for wp in self.route.wpList] if self.route.legList: angList = [Angle(self.route.legList[0].absCourse + 180.0)] prevAng = self.route.legList[0].absCourse for leg in self.route.legList[1:]: newAng = Angle(leg.absCourse + 180.0) angList.append((prevAng + newAng) / 2.0) # average angles if abs(prevAng - newAng) > 180: angList[-1] = Angle(angList[-1] + 180.0) prevAng = leg.absCourse angList.append(prevAng) octantList = [int(round(ang / 45.0)) for ang in angList] for i in range(len(self.routeList)): self.routeList[i].labelOctant = octantList[i] if octantList[i] == 8: self.routeList[i].labelOctant = 0 def addAirports(self): """Add additional airports from the database to the map list""" self.airportList = [MapItem(wp, self) for wp in \ Airport().getAllWaypoints() if self.isOnMap(wp)] def addNavaids(self): """Add additional navaids from the database to the map list""" self.navaidList = [MapItem(wp, self) for wp in \ Navaid().getAllWaypoints() if self.isOnMap(wp)] def addFixes(self): """Add additional fixes from the database to the map list""" self.fixList = [MapItem(wp, self) for wp in \ Fixpoint().getAllWaypoints() if self.isOnMap(wp)] def isOnMap(self, wp): """Return 1 if wp is within map bounds""" return self.minLat <= wp.latitudeValue() <= self.maxLat \ and self.minLng <= abs(wp.longitudeValue()) <= self.maxLng class MapItem: """Stores data for an item included on the map""" def __init__(self, waypoint, mapData): self.waypoint = waypoint self.xCoord = MapData.mapPixels - \ int((abs(self.waypoint.longitudeValue()) \ - mapData.minLng) \ / (mapData.maxLng - mapData.minLng) \ * MapData.mapPixels) self.yCoord = MapData.mapPixels - \ int((self.waypoint.latitudeValue() - mapData.minLat) \ / (mapData.maxLat - mapData.minLat) \ * MapData.mapPixels) self.labelOctant = 4 # default label position for route labels