def test_get_point_hash(self): from editolido.geoindex import GeoGridIndex grid = GeoGridIndex(4) self.assertEqual(grid.get_point_hash(LatLng(45, 10)), 'u0p0') self.assertEqual(grid.get_point_hash(GeoPoint((45, 10))), 'u0p0') grid = GeoGridIndex() self.assertEqual(grid.get_point_hash(LatLng(45, 10)), 'u0p')
def test_wmo_importer(self): from editolido.geoindex import GeoGridIndex, wmo_importer wmo_grid = GeoGridIndex() for name, _, lon, lat in wmo_importer(): wmo_grid.add_point( GeoPoint(LatLng(lat, lon), name, normalizer=None)) self.assertTrue(len(wmo_grid.data) > 5000)
def test_get_nearest_points(self): center_point = GeoPoint([49, 2]) wmo_grid = GeoGridIndex() wmo_grid.load() nearest = list(wmo_grid.get_nearest_points(center_point, 27)) self.assertEqual(len(nearest), 1) self.assertEqual(nearest[0][0].name, "07145")
def test_get_nearest_points_dirty(self): center_point = GeoPoint([49, 2]) wmo_grid = GeoGridIndex() wmo_grid.load() # with self.assertRaises(ValueError): # wmo_grid.get_nearest_points_dirty(center_point, 100) nearest = list(wmo_grid.get_nearest_points_dirty(center_point, 75)) self.assertEqual(len(nearest), 42)
def test_get_nearest_points(self): from editolido.geoindex import GeoGridIndex c = GeoPoint((45, 10.5)) p = GeoPoint((45, 10)) # à 21,23NM grid = GeoGridIndex() grid.add_point(p) nearby = grid.get_nearest_points(c, 20, converter=nm_to_rad) self.assertEqual(list(nearby), []) nearby = grid.get_nearest_points(c, 23, converter=nm_to_rad) self.assertEqual(list(nearby), [(p, c.distance_to(p, converter=rad_to_nm))])
def ogimet_route(route, segment_size=300, debug=False, name="", description=""): wmo_grid = GeoGridIndex() wmo_grid.load() start = route[0] end = route[-1] def print_ogimet(points): print('Route Ogimet (%s): %s' % ( len(points), '_'.join([p.name for p in points]))) # noinspection PyShadowingNames def build_ogimet(default_step): ogimet_sites = [start.name] previous = start ogimet_points = [start] sid = True for i, p in enumerate( route.split(60, converter=km_to_rad, preserve=True)): if i == 0: continue neighbours = sorted( wmo_grid.get_nearest_points(p, 30, converter=km_to_rad), key=lambda t: t[1]) if neighbours: point, d = neighbours[0] if sid and point.distance_to(start, converter=rad_to_km) < 500: step = min(60, default_step) else: sid = False step = default_step if point.name not in ogimet_sites and previous.distance_to( point, converter=rad_to_km) > step: previous = point ogimet_points.append(point) ogimet_sites.append(point.name) ogimet_points[-1] = end return ogimet_points step = start.distance_to(end, converter=rad_to_km) / 200 ogimet_points = [] while True: ogimet_points = build_ogimet(step) if len(ogimet_points) < 23: break if debug: print_ogimet(ogimet_points) step *= 2 if debug: print_ogimet(ogimet_points) return Route(ogimet_points).split( segment_size, preserve=True, name=name, description=description)
def test_get_nearest_points_dirty(self): from editolido.geoindex import GeoGridIndex c = GeoPoint((45, 10.5)) p = GeoPoint((45, 10)) # à 21,23NM grid = GeoGridIndex(4) grid.add_point(p) with self.assertRaises(ValueError): grid.get_nearest_points_dirty(c, 30, converter=nm_to_rad) grid = GeoGridIndex() grid.add_point(p) nearby = grid.get_nearest_points_dirty(c, 20, converter=nm_to_rad) self.assertEqual(list(nearby), [p])
def test_dumps(self): p = GeoPoint((45, 10), name='P1', description='D2') grid = GeoGridIndex() self.assertEqual(grid.dumps(), '{}') grid.add_point([p.name, float(p.latitude), float(p.longitude)]) grid.data['__test__'] = 'test' # test default encoder is called jsondata = grid.dumps() self.assertDictEqual(grid.data, json.loads(jsondata, encoding='utf-8'))
def test_dumps(self): from editolido.geoindex import GeoGridIndex p = GeoPoint((45, 10), name='P1', description='D2') grid = GeoGridIndex() self.assertEqual(grid.dumps(), '{}') grid.add_point(p) grid.data['__test__'] = 'test' # test default encoder is called jsondata = grid.dumps() self.assertDictEqual( grid.data, json.loads(jsondata, encoding='utf-8', object_hook=as_geopoint))
def test_get_nearest_points(self): c = GeoPoint((45, 10.5)) p = GeoPoint((45, 10)) # à 21,23NM grid = GeoGridIndex() grid.add_point([p.name, float(p.latitude), float(p.longitude)]) nearby = grid.get_nearest_points(c, 20, converter=nm_to_rad) if six.PY2: self.assertEqual(list(nearby), []) else: pass # TODO nearby = grid.get_nearest_points(c, 23, converter=nm_to_rad) if six.PY2: self.assertEqual(list(nearby), [(p, c.distance_to(p, converter=rad_to_nm))]) else: pass # TODO
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 main(): # pragma: no cover wmo_grid = GeoGridIndex() for name, lon, lat in wmo_importer(): wmo_grid.add_point(GeoPoint(LatLng(lat, lon), name, normalizer=None)) wmo_grid.save()
def test_wmo_importer(self): wmo_grid = GeoGridIndex() for name, _, lon, lat in wmo_importer(): wmo_grid.add_point( GeoPoint(LatLng(lat, lon), name, normalizer=None)) self.assertTrue(len(wmo_grid.data) > 5000)
def test_load(self): grid = GeoGridIndex() grid.load() self.assertGreater(len(grid.data), 4000)
def test_get_nearest_points_dirty(self): c = GeoPoint((45, 10.5)) p = GeoPoint((45, 10)) # à 21,23NM grid = GeoGridIndex(4) print(grid.precision, rad_to_km(grid.grid_size)) grid.add_point([p.name, float(p.latitude), float(p.longitude)]) with self.assertRaises(ValueError): grid.get_nearest_points_dirty(c, 30, converter=nm_to_rad) grid = GeoGridIndex() grid.add_point([p.name, float(p.latitude), float(p.longitude)]) nearby = grid.get_nearest_points_dirty(c, 20, converter=nm_to_rad) self.assertEqual(list(nearby), [p])
def test_add_point(self): grid = GeoGridIndex(4) p = ["", 45, 10] grid.add_point(p) self.assertEqual(grid.data['u0p0'], [p])
def test_get_point_hash(self): grid = GeoGridIndex(4) self.assertEqual(grid.get_point_hash(LatLng(45, 10)), 'u0p0') self.assertEqual(grid.get_point_hash(GeoPoint((45, 10))), 'u0p0') grid = GeoGridIndex() self.assertEqual(grid.get_point_hash(LatLng(45, 10)), 'u0p')
def test_add_point(self): from editolido.geoindex import GeoGridIndex grid = GeoGridIndex(4) p = GeoPoint((45, 10)) grid.add_point(p) self.assertEqual(grid.data['u0p0'], [p])
def test_load(self): from editolido.geoindex import GeoGridIndex grid = GeoGridIndex() grid.load() self.assertGreater(len(grid.data), 4000)