def test_tracks_with_fishpoints(self): ofp = load_ofp(DATADIR + '/KJFK-LFPG 27Mar2015 05:45z OFP.txt') tracks = list(ofp.tracks(fishfile=FISHFILE)) self.assertEqual(len(tracks), 9) self.assertEqual( tracks[0], Route([ GeoPoint((55.000000, -15.000000), name="RESNO"), GeoPoint((56.000000, -20.000000)), GeoPoint((57.000000, -30.000000)), GeoPoint((58.000000, -40.000000)), GeoPoint((58.000000, -50.000000)), GeoPoint((56.700000, -57.000000), name="CUDDY") ])) self.assertEqual( tracks[-1], Route([ GeoPoint((42.000000, -40.000000)), GeoPoint((38.000000, -50.000000)), GeoPoint((33.000000, -60.000000)), GeoPoint((32.670000, -61.190000), name="NUMBR") ])) for p in tracks[0]: self.assertTrue(p.name) self.assertTrue(tracks[0].name.endswith('A')) self.assertTrue(tracks[-1].name.endswith('J'))
def tests_tracks_rlat_new_format(self): ofp = load_ofp(DATADIR + '/AF009_KJFK-LFPG_18Mar2016_04:55z_OFP_12_0_1.txt') tracks = list(ofp.tracks()) self.assertEqual(len(tracks), 7) self.assertEqual( tracks[0], Route([ GeoPoint((50, -50)), GeoPoint((51, -40)), GeoPoint((52, -30)), GeoPoint((53, -20)) ])) self.assertFalse(tracks[0].is_complete) self.assertEqual( tracks[2], Route([ GeoPoint((48.5, -50)), GeoPoint((49.5, -40)), GeoPoint((50.5, -30)), GeoPoint((51.5, -20)) ])) self.assertFalse(tracks[2].is_complete) self.assertTrue(tracks[0].name.endswith('T')) self.assertTrue(tracks[-1].name.endswith('Z'))
def tests_tracks_rlat_new_format_with_fishpoints(self): ofp = load_ofp(DATADIR + '/AF009_KJFK-LFPG_18Mar2016_04:55z_OFP_12_0_1.txt') tracks = list(ofp.tracks(fishfile=FISHFILE)) self.assertEqual(len(tracks), 7) self.assertEqual( tracks[0], Route([ GeoPoint((49.500000, -52.000000), name="ELSIR"), GeoPoint((50, -50)), GeoPoint((51, -40)), GeoPoint((52, -30)), GeoPoint((53, -20)), GeoPoint((53.000000, -15.000000), name="MALOT"), GeoPoint((53.000000, -14.000000), name="GISTI") ])) self.assertTrue(tracks[0].is_complete) self.assertEqual( tracks[2], Route([ GeoPoint((48.000000, -52.000000), name="MUSAK"), GeoPoint((48.5, -50)), GeoPoint((49.5, -40)), GeoPoint((50.5, -30)), GeoPoint((51.5, -20)), GeoPoint((51.5, -15.000000), name="ADARA"), GeoPoint((51.5, -14.000000), name="LEKVA") ])) self.assertTrue(tracks[2].is_complete) self.assertTrue(tracks[0].name.endswith('T')) self.assertTrue(tracks[-1].name.endswith('Z'))
def test_equal(self): self.assertEqual( Route([GeoPoint((0, 0)), GeoPoint((0, 90))]), Route([GeoPoint((0.0000001, 0.0000001)), GeoPoint((0, 90))]), ) self.assertNotEqual( Route([GeoPoint((0, 0)), GeoPoint((0, 90))]), Route([GeoPoint((0.1, 0)), GeoPoint((0, 90))]), ) self.assertNotEqual( Route([GeoPoint((0, 0)), GeoPoint((0, 90))]), Route([GeoPoint((0, 0.1)), GeoPoint((0, 90))]), ) self.assertNotEqual( Route([GeoPoint((0, 0)), GeoPoint((0, 90))]), Route([GeoPoint((0, 0)), GeoPoint((0, 90)), GeoPoint((0, 180))]), ) self.assertNotEqual( Route([GeoPoint((0, 0)), GeoPoint((0, 90)), GeoPoint((0, 180))]), Route([GeoPoint((0, 0)), GeoPoint((0, 90))]), )
def test_slice(self): def generator(): # pragma no cover return # noinspection PyUnreachableCode yield "dummy generator" route = Route(generator()) self.assertFalse(route) self.assertEqual([], route[1:]) self.assertEqual([], route[:]) route = Route([GeoPoint((0, 0)), GeoPoint((0, 90))]) self.assertEqual([GeoPoint((0, 90))], route[1:])
def test_segments(self): a = GeoPoint((0, 0)) b = GeoPoint((0, 90)) c = GeoPoint((0, 180)) route = Route([a, b, c], ) self.assertEqual(list(route.segments), [(a, b), (b, c)]) route = Route([a, b], ) self.assertEqual(list(route.segments), [(a, b)]) route = Route() self.assertEqual(list(route.segments), []) route = Route([a, c]) self.assertEqual(list(route.segments), [(a, c)])
def test_distance(self): route = Route() self.assertAlmostEqual(route.distance(converter=None), 0) a = GeoPoint((0, 0)) b = GeoPoint((0, 90)) c = GeoPoint((0, 180)) route = Route([a, b, c]) self.assertAlmostEqual(route.distance(converter=None), math.pi) route = Route([c, b, a]) self.assertAlmostEqual(route.distance(converter=None), math.pi) route = Route([a, c]) self.assertAlmostEqual(route.distance(converter=None), math.pi) d = GeoPoint((-90, 0)) route = Route([a, d, c]) self.assertAlmostEqual(route.distance(converter=None), math.pi)
def add_sigmets(kml, folder, jsondata): from editolido.geopoint import GeoPoint from editolido.route import Route for d in jsondata['features']: props = d['properties'] geom = d['geometry'] name = "{firName}: {qualifier} {hazard}".format(**props) description = "{rawSigmet}".format(**props) if geom['type'] == 'LineString': geom['coordinates'] = [geom['coordinates']] if geom['type'] in ('Polygon', 'LineString'): for area in geom['coordinates']: route = Route( [GeoPoint((lat, lon)) for lon, lat in area], name=name, description=description ) kml.add_line(folder, route) kml.add_point( folder, GeoPoint.get_center( route, name=name, description=description), ) elif geom['type'] == 'Point': kml.add_point( folder, GeoPoint( (geom['coordinates'][1], geom['coordinates'][0]), name=name, description=description), ) else: print(d) print('unknown geometry type: %s' % geom['type']) raise ValueError
def test_add_line(self): kml = KMLGenerator(line_template="{name} {color}") kml.add_folder('aFolder') from editolido.route import Route from editolido.geopoint import GeoPoint route = Route([GeoPoint((0, 0)), GeoPoint((0, 90))], name="route") kml.add_line('aFolder', route, color="blouge") self.assertEqual(kml.folders['aFolder'][0], 'route blouge')
def test_add_points(self): kml = KMLGenerator(point_template="{name}{color}") kml.add_folder('aFolder') from editolido.route import Route from editolido.geopoint import GeoPoint route = Route([GeoPoint((0, 0)), GeoPoint((0, 90))], name="route") kml.add_points('aFolder', route, color="blouge") self.assertEqual(''.join(kml.folders['aFolder']), 'N0000.0W00000.0blougeN0000.0E09000.0blouge')
def tests_tracks_with_page_break_and_fishpoints(self): ofp = load_ofp(DATADIR + '/AF011_KJFK-LFPG_22Mar2016_02:45z_OFP_8_0_1.txt') tracks = list(ofp.tracks(fishfile=FISHFILE)) self.assertEqual(len(tracks), 8) self.assertEqual( tracks[0], Route([ GeoPoint((50.500000, -52.000000), name="ALLRY"), GeoPoint((51, -50)), GeoPoint((52, -40)), GeoPoint((54, -30)), GeoPoint((56, -20)), GeoPoint((56.000000, -15.000000), name="PIKIL"), GeoPoint((56.000000, -14.000000), name="SOVED") ])) self.assertTrue(tracks[0].is_complete) self.assertEqual(tracks[6].name, 'NAT Y') self.assertEqual( tracks[6], # Y Route([ GeoPoint((40.120000, -67.000000), name="JOBOC"), GeoPoint((40, -60)), GeoPoint((41, -50)), GeoPoint((41, -40)) ])) self.assertTrue(tracks[6].is_complete) self.assertEqual(tracks[4].name, 'NAT W') # FPL Track self.assertEqual( tracks[4], # W Route([ GeoPoint((46.500000, -52.000000), name="PORTI"), GeoPoint((47, -50)), GeoPoint((48, -40)), GeoPoint((50, -30)), GeoPoint((52, -20)), GeoPoint((52.000000, -15.000000), name="LIMRI"), GeoPoint((52.000000, -14.000000), name="XETBO"), ])) self.assertTrue(tracks[4].is_complete) self.assertTrue(tracks[0].name.endswith('S')) self.assertTrue(tracks[-1].name.endswith('Z'))
def test_add_segments(self): kml = KMLGenerator(point_template="{name}{color}") kml.add_folder('aFolder') from editolido.route import Route from editolido.geopoint import GeoPoint route = Route([GeoPoint((0, 0), name='p1'), GeoPoint((45, 90), name='p2'), GeoPoint((0, 90), name='p3')], name="route") kml.add_points('aFolder', route, color="blouge") self.assertEqual(''.join(kml.folders['aFolder']), 'p1blougep2blougep3blouge')
def test_tracks(self): ofp = load_ofp(DATADIR + '/KJFK-LFPG 27Mar2015 05:45z OFP.txt') tracks = list(ofp.tracks()) self.assertEqual(len(tracks), 9) self.assertEqual( tracks[0], Route([ GeoPoint((56.000000, -20.000000)), GeoPoint((57.000000, -30.000000)), GeoPoint((58.000000, -40.000000)), GeoPoint((58.000000, -50.000000)) ])) self.assertEqual( tracks[-1], Route([ GeoPoint((42.000000, -40.000000)), GeoPoint((38.000000, -50.000000)), GeoPoint((33.000000, -60.000000)) ])) for p in tracks[0]: self.assertTrue(p.name) self.assertTrue(tracks[0].name.endswith('A')) self.assertTrue(tracks[-1].name.endswith('J'))
def test_as_kml_line(self): kml = KMLGenerator( line_template='{name}/{style}/{description}/{coordinates}',) from editolido.geopoint import GeoPoint from editolido.route import Route start = GeoPoint((0, 0)) end = GeoPoint((0, 90)) route = Route( [start, end], name="route_name", description="route_description") kml.add_folder('aFolder') kml.add_line('aFolder', route, style='route_style') self.assertEqual( ''.join(kml.folders['aFolder']), 'route_name/route_style/route_description/' '0.000000,0.000000 90.000000,0.000000' )
def test_as_kml_points(self): kml = KMLGenerator( point_template='{name}/{style}/{description}/{coordinates}',) from editolido.geopoint import GeoPoint from editolido.route import Route start = GeoPoint((0, 0), name="P1") end = GeoPoint((0, 90), name="P2", description="D2") route = Route( [start, end], name="route_name", description="route_description") kml.add_folder('aFolder') kml.add_points('aFolder', route, style='point_style') self.assertEqual( '\n'.join(kml.folders['aFolder']), 'P1/point_style//0.000000,0.000000\n' 'P2/point_style/D2/90.000000,0.000000' )
def test_tracks(self): ofp = load_ofp( DATADIR + '/AF 010_LFPG-KJFK_27Sep2019_1450z_OFP_6_nvp_pdfminer.txt') tracks = list(ofp.tracks()) self.assertEqual(len(tracks), 5) self.assertEqual( tracks[0], Route([ GeoPoint((59.000000, -20.000000)), GeoPoint((59.000000, -30.000000)), GeoPoint((58.000000, -40.000000)), GeoPoint((56.000000, -50.000000)) ])) for p in tracks[0]: self.assertTrue(p.name) self.assertTrue(tracks[0].name.endswith('A')) self.assertTrue(tracks[-1].name.endswith('E'))
def test_tracks(self): ofp = load_ofp( DATADIR + '/AF342_LFPG-CYUL_30Jul2019_14-00z_OFP7_0_1_pdfminer.txt') tracks = list(ofp.tracks()) self.assertEqual(len(tracks), 6) self.assertEqual( tracks[0], Route([ GeoPoint((62.000000, -20.000000)), GeoPoint((63.000000, -30.000000)), GeoPoint((64.000000, -40.000000)), GeoPoint((63.000000, -50.000000)) ])) for p in tracks[0]: self.assertTrue(p.name) self.assertTrue(tracks[0].name.endswith('A')) self.assertTrue(tracks[-1].name.endswith('F'))
def test_split(self): route = Route() self.assertEqual(list(route.split(60).segments), []) start = GeoPoint((0, 0)) end = GeoPoint((0, 90)) route = Route([start, end]) size = route.distance() / 2 middle = GeoPoint((0, 45)) self.assertEqual(list(route.split(size).segments), [(start, middle), (middle, end)]) a = GeoPoint((0, 10)) b = GeoPoint((0, 55)) route = Route([start, a, end]) self.assertEqual(list(route.split(size).segments), [(start, middle), (middle, end)]) self.assertEqual(list(route.split(size, preserve=True).segments), [(start, a), (a, b), (b, end)]) route = Route([start, a, middle, end]) self.assertEqual(list(route.split(size).segments), [(start, middle), (middle, end)]) self.assertEqual(list(route.split(size, preserve=True).segments), [(start, a), (a, middle), (middle, end)]) # check we yield the last point p = GeoPoint((0, 46.66554361)) self.assertEqual(route.split(size + 100), Route([start, p, end]))
def test_split(self): route = Route() self.assertEqual(list(route.split(60).segments), []) start = GeoPoint((0, 0)) end = GeoPoint((0, 90)) route = Route([start, end]) size = route.distance() / 2 middle = GeoPoint((0, 45)) self.assertEqual( list(route.split(size).segments), [(start, middle), (middle, end)]) a = GeoPoint((0, 10)) b = GeoPoint((0, 55)) route = Route([start, a, end]) self.assertEqual( list(route.split(size).segments), [(start, middle), (middle, end)]) self.assertEqual( list(route.split(size, preserve=True).segments), [(start, a), (a, b), (b, end)]) route = Route([start, a, middle, end]) self.assertEqual( list(route.split(size).segments), [(start, middle), (middle, end)]) self.assertEqual( list(route.split(size, preserve=True).segments), [(start, a), (a, middle), (middle, end)]) # check we yield the last point p = GeoPoint((0, 46.66554361)) self.assertEqual(route.split(size + 100), Route([start, p, end]))
def test_distance(self): route = Route() self.assertAlmostEqual(route.distance(converter=None), 0) a = GeoPoint((0, 0)) b = GeoPoint((0, 90)) c = GeoPoint((0, 180)) route = Route([a, b, c]) self.assertAlmostEqual(route.distance(converter=None), math.pi) route = Route([c, b, a]) self.assertAlmostEqual(route.distance(converter=None), math.pi) route = Route([a, c]) self.assertAlmostEqual(route.distance(converter=None), math.pi) d = GeoPoint((-90, 0)) route = Route([a, d, c]) self.assertAlmostEqual(route.distance(converter=None), math.pi)
def route(self): """ Return a Route of the wpt_coordinates """ return self._route or Route(self.wpt_coordinates())
def ogimet_route(route, segment_size=300, name="", description=""): Result = namedtuple('Result', ['fpl', 'ogimet']) wmo_grid = GeoGridIndex() wmo_grid.load() neighbour_radius = (rad_to_km(wmo_grid.grid_size) / 2.0) - 0.1 def get_neighbour(point): """ Find neighbour ogimet point Prefer fpl point if it exists :param point: :return: tuple(Geopoint, float) """ neighbours = sorted( wmo_grid.get_nearest_points(point, neighbour_radius), key=lambda t: t[1] ) if neighbours: if point.name in [n.name for n, _ in neighbours]: return point, 0 return neighbours[0][0], neighbours[0][1] return None, None def find_strategic(start, end, results): """ Find point you can not suppress without increasing xtd :param start: int :param end: int :param results: [Result] :return: """ # search in reverse order to stop at the latest point in the route direction # in segment [i, j] we try to remove inner elements by checking the xtd for k in range(end - 1, start, -1): # xtd from ogimet point to fpl segment o_xtd = results[k].ogimet.xtd_to( (results[k].fpl, results[k + 1].fpl) ) # xtd from fpl point to ogimet segment f_xtd = results[k].fpl.xtd_to( (results[start].ogimet, results[end].ogimet) ) if abs(f_xtd) > abs(o_xtd): return k return None def filter_by_xtd(results): """ Here we keep significant ogimet points. By significant, I mean points which increase the xtd if missing. The algorithm is recursive, if route is A B C D E F and ogimet route found is A B'C'D'E'F We try to suppress B', if successful we try to suppress C' and so on For example if B', C' and E' are not relevant the loop will try to suppress B' and C', then it will keep D' and start again from D' to suppress E' and keep F At the end we try again (recursion) until the route size is constant. For information a typical NAT route will reduce from 26 to 15 points and a flight to NRT will end with 26 points (starting from 79) :param results: [Result] :return: [Result] """ res = [results[0]] i = -1 while i < (len(results) - 1): i += 1 j = i + 2 # we try to remove many consecutive points until it fails while j <= len(results) - 1: k = find_strategic(i, j, results) if k is None: j += 1 # no significant point yet, try to extend to next else: # a significant point was found, store it if results[k].ogimet.name not in [o.name for _, o in res]: res.append(results[k]) i = k - 1 # will start at k on next round break res.append(results[-1]) # recursion works, so try it until there is no change if len(res) < len(results): return filter_by_xtd(res) else: return res # noinspection PyUnusedLocal def lowest_crs_index(results): """ Index to the point which causes the smallest course change if removed :param results: [Result] :return: int """ best_diff = 0 best = None maxi = len(results) - 1 for i, r in enumerate(results): if 1 <= i < maxi: diff = abs( results[i - 1].ogimet.course_to(results[i].ogimet) - results[i - 1].ogimet.course_to(results[i+1].ogimet) ) if best is None or diff < best_diff: best = i best_diff = diff return best def lowest_xtd_index(results): """ Index to the point which causes the less xtd loss if removed :param results: [Result] :return: int """ best_xtd = 0 best = None maxi = len(results) - 1 for i, r in enumerate(results): if 1 <= i < maxi: xtd = abs( r.fpl.xtd_to((results[i - 1].ogimet, results[i + 1].ogimet)) ) if best is None or xtd < best_xtd: best = i best_xtd = xtd return best # Here we find all ogimet points for our route # The same ogimet point can be used by many fpl points # prepare o_index which will be used to deduplicate # we place in o_index points with the shortest distance ogimet_results = [] o_index = {} for p in route.split(60, converter=km_to_rad, preserve=True): neighbour, x = get_neighbour(p) if neighbour: if neighbour.name in o_index: if o_index[neighbour.name][0] > x: o_index[neighbour.name] = (x, p) else: o_index[neighbour.name] = (x, p) ogimet_results.append(Result(p, neighbour)) # filter using o_index (keep points that were stored in o.index) ogimet_results = list( filter(lambda r: o_index[r.ogimet.name][1] == r.fpl, ogimet_results) ) # keep only significant points (strategic points) ogimet_results = filter_by_xtd(ogimet_results) # Reduce ogimet route size to 22 points # We have to loose precision, we score the lowest xtd loss # as an alternative you may use lowest_crs_index but I did # not find major gain yet. while len(ogimet_results) > 21: idx = lowest_xtd_index(ogimet_results) ogimet_results = ogimet_results[:idx] + ogimet_results[idx+1:] return Route(points=[ogimet for _, ogimet in ogimet_results]).split( segment_size, preserve=True, name=name, description=description)
def test_get_item(self): route = Route([GeoPoint((0, 0)), GeoPoint((0, 90))]) self.assertEqual(route[0], GeoPoint((0, 0))) self.assertEqual(route[-1], GeoPoint((0, 90)))
def lido2mapsme(action_in, params, use_segments=False, kmlargs=None, debug=False, fishfile=None): """ Lido2Mapsme KML rendering action :param fishfile: absolute path to a fishfile or None :param action_in: unicode action input :param params: dict action's parameters :param use_segments: plot route as LineString segments instead of a single LineString (Avenza fix) :param kmlargs: optional dictionnary for KML Generator :param debug: bool determines wether or not to print ogimet debug messages :return: """ from editolido.constants import NAT_POSITION_ENTRY, PIN_NONE from editolido.fishpoint import find_fishfile from editolido.geopoint import GeoPoint from editolido.kml import KMLGenerator from editolido.ofp import OFP from editolido.route import Route ofp = OFP(action_in) if kmlargs: kml = KMLGenerator(**kmlargs) else: kml = KMLGenerator() pin_rnat = params.get('Repère NAT', PIN_NONE) pin_rmain = params.get('Point Route', PIN_NONE) pin_ralt = params.get('Point Dégagement', PIN_NONE) kml.add_folders('greatcircle', ('rnat', pin_rnat), ('rnat_incomplete', pin_rnat), ('ralt', pin_ralt), ('rmain', pin_rmain)) route_name = "{departure}-{destination}".format(**ofp.infos) route = ofp.route route.name = route_name route.description = ofp.description # set route/line plot method add_kml_route = kml.add_segments if use_segments else kml.add_line natmarks = [] if params.get('Afficher NAT', False): pin_pos = 0 if params['Position repère'] == NAT_POSITION_ENTRY else -1 fishfile = fishfile if fishfile else find_fishfile() if debug: print("using fish points file %s\n" % fishfile) for track in ofp.tracks(fishfile=fishfile): if track: folder = 'rnat_incomplete' if not track.is_complete else 'rnat' add_kml_route(folder, track) if pin_rnat != PIN_NONE: if track.is_mine: p = GeoPoint(track[0], name=track.name, description=track.description) natmarks.append(p) kml.add_point(folder, p, style=pin_rnat) p = GeoPoint(track[-1], name=track.name, description=track.description) natmarks.append(p) kml.add_point(folder, p, style=pin_rnat) else: p = GeoPoint(track[pin_pos], name=track.name, description=track.description) natmarks.append(p) kml.add_point(folder, p, style=pin_rnat) else: print("empty track found %s" % track.name) if params.get('Afficher Ortho', False): greatcircle = Route( (route[0], route[-1])).split(300, name="Ortho %s" % route_name) add_kml_route('greatcircle', greatcircle) add_kml_route('rmain', route) if pin_rmain != PIN_NONE: kml.add_points('rmain', route, excluded=natmarks, style=pin_rmain) if params.get('Afficher Dégagement', False): alt_route = Route(ofp.wpt_coordinates_alternate(), name="Route Dégagement") add_kml_route('ralt', alt_route) if pin_ralt != PIN_NONE: kml.add_points('ralt', alt_route[1:], style=pin_ralt) kml = kml.render( name=ofp.description, rnat_color=params.get('Couleur NAT', '') or '60DA25A8', ogimet_color=params.get('Couleur Ogimet', '') or '40FF0000', greatcircle_color=params.get('Couleur Ortho', '') or '5F1478FF', rmain_color=params.get('Couleur Route', '') or 'FFDA25A8', ralt_color=params.get('Couleur Dégagement', '') or 'FFFF00FF', rnat_incomplete_color=params.get('Couleur NAT incomplet', '') or 'FF0000FF', ) try: # noinspection PyUnresolvedReferences import clipboard # EDITORIAL Module json_results = { 'type': '__editolido__.extended_clipboard', 'lido_route': ' '.join(ofp.lido_route), 'kml': kml, } clipboard.set(json.dumps(json_results)) except ImportError: pass return kml