def test_find_extreme_point_indicies(self): # A line of Lat Longs around the Equator LATITUDES = np.zeros(10, dtype=float) LONGITUDES = np.array([-5 + i for i in range(10)], dtype=float) ecef_points_0 = global_Point3d(LATITUDES, LONGITUDES) indicies_0 = find_extreme_point_indicies( ecef_points_0, threshold=ACROSS_TRACK_TOLERANCE, xtd_ratio=0.1) self.assertEqual(len(indicies_0), 2) assert_array_almost_equal(indicies_0, [0, 9]) LATITUDES[4] = 1 LATITUDES[8] = -1 ecef_points_1 = global_Point3d(LATITUDES, LONGITUDES) indicies_1 = find_extreme_point_indicies( ecef_points_1, threshold=ACROSS_TRACK_TOLERANCE, xtd_ratio=0.1) self.assertEqual(len(indicies_1), 7) assert_array_almost_equal(indicies_1, [0, 3, 4, 5, 7, 8, 9]) indicies_3 = find_extreme_point_indicies(ecef_points_1, threshold=np.deg2rad(1.0), xtd_ratio=0.1) self.assertEqual(len(indicies_3), 7)
def test_fit_arc_to_points(self): LATS_0 = np.zeros(4, dtype=np.float) LONS_0 = np.array([0.0, 1.0, 2.0, 3.0]) # Test points along arc ecef_points_0 = global_Point3d(LATS_0, LONS_0) ecef_arc_0 = Arc3d(ecef_points_0[0], ecef_points_0[-1]) new_arc_0 = fit_arc_to_points(ecef_points_0, ecef_arc_0) assert_almost_equal(distance_radians(new_arc_0.a(), ecef_arc_0.a()), 0.0) assert_almost_equal(distance_radians(new_arc_0.b(), ecef_arc_0.b()), 0.0) # Test slope away from start of arc ecef_points_1 = global_Point3d(LONS_0, LONS_0) ecef_arc_1 = Arc3d(ecef_points_1[0], ecef_points_1[-1]) new_arc_1 = fit_arc_to_points(ecef_points_1, ecef_arc_0) assert_almost_equal(distance_radians(new_arc_1.a(), ecef_arc_0.a()), 0.0) assert_almost_equal( distance_radians(new_arc_1.pole(), ecef_arc_1.pole()), 0.0) # Test slope towards end of arc LATS_2 = np.array([3.0, 2.0, 1.0, 0.0]) ecef_points_2 = global_Point3d(LATS_2, LONS_0) ecef_arc_2 = Arc3d(ecef_points_2[0], ecef_points_2[-1]) new_arc_2 = fit_arc_to_points(ecef_points_2, ecef_arc_0) assert_almost_equal( distance_radians(new_arc_2.pole(), ecef_arc_2.pole()), 0.0) assert_almost_equal(distance_radians(new_arc_2.b(), ecef_arc_0.b()), 0.0)
def test_find_extreme_point_index_3(self): # A line of Lat Longs around the Equator LATITUDES = np.zeros(10, dtype=float) LONGITUDES = np.array(range(-5, 5), dtype=float) ecef_points_0 = global_Point3d(LATITUDES, LONGITUDES) # same point max_index = len(ecef_points_0) - 1 result_0 = find_extreme_point_index(ecef_points_0, 0, max_index, threshold=ACROSS_TRACK_TOLERANCE, xtd_ratio=0.1, calc_along_track=True) self.assertEqual(result_0, max_index) # route "doubles back" on itself LONGITUDES[-1] = LONGITUDES[-3] ecef_points_1 = global_Point3d(LATITUDES, LONGITUDES) result_1 = find_extreme_point_index(ecef_points_1, 0, max_index, threshold=ACROSS_TRACK_TOLERANCE, xtd_ratio=0.1, calc_along_track=True) self.assertEqual(result_1, max_index - 1)
def test_find_extreme_point_along_track_index(self): # A line of Lat Longs around the Equator LATITUDES = np.zeros(10, dtype=float) LONGITUDES = np.array(range(-5, 5), dtype=float) ecef_points_0 = global_Point3d(LATITUDES, LONGITUDES) # All points within arc arc = Arc3d(ecef_points_0[0], ecef_points_0[-1]) index_0 = find_extreme_point_along_track_index(arc, ecef_points_0, 1.0 * NM) self.assertEqual(index_0, 0) # Point 2 before start of arc LONGITUDES[2] = -6 ecef_points_1 = global_Point3d(LATITUDES, LONGITUDES) index_1 = find_extreme_point_along_track_index(arc, ecef_points_1, 1.0 * NM) self.assertEqual(index_1, 2) # Point 8 past end of arc LONGITUDES[8] = 8 ecef_points_2 = global_Point3d(LATITUDES, LONGITUDES) index_2 = find_extreme_point_along_track_index(arc, ecef_points_2, 1.0 * NM) self.assertEqual(index_2, 8)
def verify_matches(flight_matches, positions1, positions2, flight_ids, delta_time, max_speed): """ Verifies the pairs of flight ids in flight_matches by calling compare_trajectory_positions with the cpr_positions and adsb_positions of each flight against the delta_time threshold. It adds new matches to the flight_ids dicts and returns the number of newly matched flights. """ matches = 0 next_pos_match = pd.merge(positions2, flight_matches, left_index=True, right_on='FLIGHT_ID_y') for next_id, next_pos in next_pos_match.groupby('FLIGHT_ID_y'): # Ensure that next_pos is new has more than one value! if next_id not in flight_ids and \ isinstance(next_pos['TIME'], pd.Series): next_times = next_pos['TIME'].values next_points = global_Point3d(next_pos['LAT'].values, next_pos['LON'].values) next_alts = next_pos['ALT'].values for prev_id in next_pos['FLIGHT_ID_x'].unique(): prev_pos = positions1.loc[prev_id] # Ensure that prev_pos has more than one value! if isinstance(prev_pos['TIME'], pd.Series): prev_times = prev_pos['TIME'].values prev_points = global_Point3d(prev_pos['LAT'].values, prev_pos['LON'].values) prev_alts = prev_pos['ALT'].values valid_match = compare_trajectory_positions( next_times, prev_times, next_points, prev_points, next_alts, prev_alts, time_threshold=delta_time, speed_threshold=max_speed) if (valid_match): matches += 1 flight_ids[next_id] = prev_id return matches
def test_find_extreme_point_index_2(self): # A line of Lat Longs by the Equator LATITUDES = np.array([0.0, -0.001, 0.01, -0.001, 0.0]) LONGITUDES = np.array([0.0, 0.0005, 0.001, 0.0014, 0.0015]) ecef_points_0 = global_Point3d(LATITUDES, LONGITUDES) # mid point max_index = len(ecef_points_0) - 1 result_0 = find_extreme_point_index(ecef_points_0, 0, max_index, threshold=ACROSS_TRACK_TOLERANCE, xtd_ratio=0.1, calc_along_track=False) self.assertEqual(result_0, 2) # first half max_index = 2 result_1 = find_extreme_point_index(ecef_points_0, 0, max_index, threshold=ACROSS_TRACK_TOLERANCE, xtd_ratio=0.1, calc_along_track=False) self.assertEqual(result_1, 2) # second half max_index = len(ecef_points_0) - 1 result_2 = find_extreme_point_index(ecef_points_0, 2, max_index, threshold=ACROSS_TRACK_TOLERANCE, xtd_ratio=0.1, calc_along_track=False) self.assertEqual(result_2, max_index)
def test_SpherePath_turn_points(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) turn_points_0 = ecef_path.turn_points(number_of_points=0) self.assertEqual(len(turn_points_0), len(ecef_path) + 8) # Ensure that start and end points are along inbound and outboud arcs arc_1 = Arc3d(ecef_points[1], ecef_points[2]) assert_almost_equal(arc_1.cross_track_distance(turn_points_0[2]), 0.0) arc_2 = Arc3d(ecef_points[2], ecef_points[3]) assert_almost_equal(arc_2.cross_track_distance(turn_points_0[3]), 0.0) assert_almost_equal(arc_2.cross_track_distance(turn_points_0[4]), 0.0) arc_last = Arc3d(ecef_points[-2], ecef_points[-1]) assert_almost_equal(arc_last.cross_track_distance(turn_points_0[-2]), 0.0) turn_points_1 = ecef_path.turn_points(number_of_points=1) self.assertEqual(len(turn_points_1), len(ecef_path) + 16) turn_points_3 = ecef_path.turn_points() self.assertEqual(len(turn_points_3), len(ecef_path) + 32) turn_points_5 = ecef_path.turn_points(number_of_points=5) self.assertEqual(len(turn_points_5), len(ecef_path) + 48)
def test_calculate_turn_initiation_distance_20(self): # A shallow turn at the Equator LATS = np.array([0.0, 0.0, 0.2]) LONS = np.array([-1.0, 0.0, 1.0]) ecef_points = global_Point3d(LATS, LONS) prev_arc = Arc3d(ecef_points[0], ecef_points[1]) arc = Arc3d(ecef_points[1], ecef_points[2]) TEN_NM = TWENTY_NM / 2 turn_0 = SphereTurnArc(prev_arc, arc, TEN_NM) turn_angle_0 = turn_0.angle distance_start = calculate_turn_initiation_distance( prev_arc, arc, turn_0.start, TWENTY_NM, ACROSS_TRACK_TOLERANCE) assert_almost_equal(distance_start, TEN_NM) distance_finish = calculate_turn_initiation_distance( prev_arc, arc, turn_0.finish, TWENTY_NM, ACROSS_TRACK_TOLERANCE) assert_almost_equal(distance_finish, TEN_NM) point_1 = turn_0.position(turn_angle_0 / 2) distance_1 = calculate_turn_initiation_distance( prev_arc, arc, point_1, TWENTY_NM, ACROSS_TRACK_TOLERANCE) assert_almost_equal(distance_1, TEN_NM, decimal=6) point_2 = turn_0.position(turn_angle_0 / 4) distance_2 = calculate_turn_initiation_distance( prev_arc, arc, point_2, TWENTY_NM, ACROSS_TRACK_TOLERANCE / 4) assert_almost_equal(distance_2, TEN_NM, decimal=6) point_3 = turn_0.position(3 * turn_angle_0 / 4) distance_3 = calculate_turn_initiation_distance( prev_arc, arc, point_3, TWENTY_NM, ACROSS_TRACK_TOLERANCE / 4) assert_almost_equal(distance_3, TEN_NM, decimal=5)
def test_SpherefPath_init(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) self.assertEqual(len(ecef_points), 12) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) self.assertEqual(len(ecef_path.points), 12) # assert_array_almost_equal(ecef_path.points, ecef_points) self.assertEqual(len(ecef_path.turn_initiation_distances), 12) assert_array_almost_equal(ecef_path.turn_initiation_distances, TURN_DISTANCES) self.assertEqual(len(ecef_path.leg_lengths), 12) assert_array_almost_equal(rad2nm(ecef_path.leg_lengths), EXPECTED_LEG_LENGTHS) self.assertEqual(len(ecef_path.turn_angles), 12) assert_array_almost_equal(np.rad2deg(ecef_path.turn_angles), EXPECTED_TURN_ANGLES) self.assertEqual(len(ecef_path.path_lengths), 12) assert_array_almost_equal(rad2nm(ecef_path.path_lengths), EXPECTED_PATH_LENGTHS) lats, lons = ecef_path.point_lat_longs() assert_array_almost_equal(lats, ROUTE_LATS) assert_array_almost_equal(lons, ROUTE_LONS) assert_array_almost_equal(ecef_path.turn_initiation_distances_nm(), rad2nm(TURN_DISTANCES))
def test_SpherePath_section_distances_and_types(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) path_distances = rad2nm(ecef_path.path_distances()) distances, types = ecef_path.section_distances_and_types() self.assertEqual(len(distances), len(ecef_path) + 8) self.assertEqual(len(types), len(ecef_path) + 8) self.assertEqual(distances[0], 0.0) self.assertEqual(types[0], PointType.Waypoint) self.assertEqual(distances[1], path_distances[1]) self.assertEqual(types[1], PointType.Waypoint) self.assertTrue(distances[2] < path_distances[2]) self.assertEqual(types[2], PointType.TurnStart) self.assertTrue(distances[3] > path_distances[2]) self.assertEqual(types[3], PointType.TurnFinish) self.assertEqual(distances[-2], path_distances[-2]) self.assertEqual(types[-2], PointType.Waypoint) self.assertEqual(distances[-1], path_distances[-1]) self.assertEqual(types[-1], PointType.Waypoint)
def test_calculate_path_cross_track_distance(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) assert_almost_equal( ecef_path.calculate_path_cross_track_distance(ecef_points[0], 0), 0.0) assert_almost_equal( ecef_path.calculate_path_cross_track_distance(ecef_points[1], 1), 0.0) xtd_2_1 = ecef_path.calculate_path_cross_track_distance( ecef_points[2], 1) assert_almost_equal(rad2nm(xtd_2_1), 4.1416795658323213) xtd_2_2 = ecef_path.calculate_path_cross_track_distance( ecef_points[2], 2) assert_almost_equal(rad2nm(xtd_2_2), 4.1416795658323213) xtd_3_2 = ecef_path.calculate_path_cross_track_distance( ecef_points[3], 2) assert_almost_equal(rad2nm(xtd_3_2), 8.2824069920496726) xtd_3_3 = ecef_path.calculate_path_cross_track_distance( ecef_points[3], 3) assert_almost_equal(rad2nm(xtd_3_3), 8.2824069920496726)
def test_SpherePath_calculate_path_leg_distance(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) # Start point distance_0 = ecef_path.calculate_path_leg_distance(ecef_points[0], 0) self.assertEqual(distance_0, 0.0) # Point at end of a straight leg distance_1_0 = ecef_path.calculate_path_leg_distance(ecef_points[1], 0) assert_almost_equal(rad2nm(distance_1_0), EXPECTED_PATH_LENGTHS[1]) # Point at start of a straight leg distance_1_1 = ecef_path.calculate_path_leg_distance(ecef_points[1], 1) self.assertEqual(distance_0, 0.0) # Point in middle of a straight leg pos_1_5 = ecef_path.calculate_position(1, 0.5) distance_1_5 = ecef_path.calculate_path_leg_distance(pos_1_5, 1) assert_almost_equal(rad2nm(distance_1_5), 0.5 * EXPECTED_PATH_LENGTHS[2]) # Point toward end of a turning leg pos_1_9 = ecef_path.calculate_position(1, 0.99) distance_1_9 = ecef_path.calculate_path_leg_distance(pos_1_9, 1) assert_almost_equal(rad2nm(distance_1_9), 0.99 * EXPECTED_PATH_LENGTHS[2]) # Before start of a turning leg distance_2_9 = ecef_path.calculate_path_leg_distance(pos_1_9, 2) assert_almost_equal(rad2nm(distance_2_9), -0.57845277761762326) # Point toward start of a turning leg pos_2_1 = ecef_path.calculate_position(2, 0.01) distance_2_1 = ecef_path.calculate_path_leg_distance(pos_2_1, 2) assert_almost_equal(rad2nm(distance_2_1), 0.01 * EXPECTED_PATH_LENGTHS[3]) # Past the ned of a turning leg distance_1_2 = ecef_path.calculate_path_leg_distance(pos_2_1, 1) self.assertTrue(rad2nm(distance_1_2) > EXPECTED_PATH_LENGTHS[2]) assert_almost_equal(rad2nm(distance_1_2), 58.980918943627351) # Point along a turning leg pos_2_75 = ecef_path.calculate_position(2, 0.75) distance_2_75 = ecef_path.calculate_path_leg_distance(pos_2_75, 2) assert_almost_equal(rad2nm(distance_2_75), 0.75 * EXPECTED_PATH_LENGTHS[3]) # Last point distance_last = ecef_path.calculate_path_leg_distance( ecef_points[-1], 10) assert_almost_equal(rad2nm(distance_last), EXPECTED_PATH_LENGTHS[11]) # # A waypoint not on path distance_2_0 = ecef_path.calculate_path_leg_distance(ecef_points[2], 1) assert_almost_equal(rad2nm(distance_2_0), EXPECTED_PATH_LENGTHS[2], decimal=4)
def test_SpherePath_calculate_position(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) pos_0 = ecef_path.calculate_position(0, 0.0) assert_almost_equal(distance_radians(pos_0, ecef_points[0]), 0.0) pos_1 = ecef_path.calculate_position(1, 0.0) assert_almost_equal(distance_radians(pos_1, ecef_points[1]), 0.0) arc2 = Arc3d(ecef_points[1], ecef_points[2]) arc3 = Arc3d(ecef_points[2], ecef_points[3]) turn_arc2 = SphereTurnArc(arc2, arc3, TURN_DISTANCES[2]) turn2_midpoint = turn_arc2.position(0.5 * abs(turn_arc2.angle)) pos_2 = ecef_path.calculate_position(2, 0.000001) assert_almost_equal(distance_radians(pos_2, turn2_midpoint), 0.0) pos_1_99999 = ecef_path.calculate_position(1, 0.99999) assert_almost_equal(distance_radians(pos_1_99999, pos_2), 0.0, decimal=6) pos_13 = ecef_path.calculate_position(13, 0.0) assert_almost_equal(distance_radians(pos_13, ecef_points[-1]), 0.0)
def test_SpherePath_subsection_positions(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) positions0 = ecef_path.subsection_positions(0, 1040.0) self.assertEqual(len(positions0), len(ecef_path)) assert_almost_equal(distance_radians(positions0[0], ecef_points[0]), 0.0) assert_almost_equal(distance_radians(positions0[-1], ecef_points[-1]), 0.0) positions1 = ecef_path.subsection_positions(0, 1000.0) self.assertEqual(len(positions1), len(ecef_path)) assert_almost_equal(distance_radians(positions1[0], ecef_points[0]), 0.0) assert_almost_equal(distance_radians(positions1[-2], ecef_points[-2]), 0.0) positions2 = ecef_path.subsection_positions(100.0, 1040.0) self.assertEqual(len(positions2), len(ecef_path) - 1) assert_almost_equal(distance_radians(positions2[1], ecef_points[2]), 0.0) assert_almost_equal(distance_radians(positions2[-1], ecef_points[-1]), 0.0)
def test_SpherePath_invalid_init(self): 'The route has a duplicate point in the middle, so closer than MIN_LENGTH' INVALID_ROUTE_LATS = np.array([1.0, 1.0, 1.0, 1.0, -1.0, 1.0]) INVALID_ROUTE_LONS = np.array([-3.0, -2.0, -1.0, -1.0, 1.0, 0.0]) invalid_points = global_Point3d(INVALID_ROUTE_LATS, INVALID_ROUTE_LONS) zero_distances = np.zeros(len(invalid_points), dtype=float) self.assertRaises(ValueError, SpherePath, invalid_points, zero_distances)
def test_SpherePath_calculate_ground_tracks(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) distances, types = ecef_path.section_distances_and_types() ground_tracks = ecef_path.calculate_ground_tracks(distances) self.assertEqual(len(ground_tracks), len(ecef_path) + 8) assert_almost_equal(ground_tracks[0], np.pi / 2, decimal=3)
def test_SpherePath_path_distances(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) path_distances = ecef_path.path_distances() self.assertEqual(len(path_distances), 12) assert_array_almost_equal(rad2nm(path_distances), EXPECTED_PATH_DISTANCES)
def test_derive_horizontal_path(self): test_data_home = env.get('TEST_DATA_HOME') self.assertTrue(test_data_home) ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = derive_horizontal_path(ecef_points, ACROSS_TRACK_TOLERANCE) self.assertEqual(len(ecef_path), 12) assert_almost_equal( distance_radians(ecef_path.points[0], ecef_points[0]), 0.0) assert_almost_equal( distance_radians(ecef_path.points[-1], ecef_points[-1]), 0.0)
def test_SpherePath_calculate_cross_track_distances(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) xtds = ecef_path.calculate_cross_track_distances( ecef_points, EXPECTED_PATH_DISTANCES) self.assertEqual(len(xtds), len(ecef_points)) assert_almost_equal(xtds[0], 0.0) assert_almost_equal(xtds[1], 0.0) assert_almost_equal(xtds[2], 4.1416795658323213) # 10NM TID assert_almost_equal(xtds[3], 8.2824069920496726) # 20NM TID assert_almost_equal(xtds[-1], 0.0)
def test_SpherePath_calculate_path_distances(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) distances = rad2nm( ecef_path.calculate_path_distances(ecef_points, ACROSS_TRACK_TOLERANCE)) self.assertEqual(len(distances), len(ecef_points)) self.assertEqual(distances[0], 0.0) assert_almost_equal(distances[11], EXPECTED_PATH_DISTANCES[11], decimal=6) assert_array_almost_equal(distances, EXPECTED_PATH_DISTANCES)
def test_find_index_and_ratio(self): ecef_points = global_Point3d(PANDAS_ICOSAHEDRON['LAT'], PANDAS_ICOSAHEDRON['LON']) point0 = ecef_points[0] index0, ratio0 = find_index_and_ratio(ecef_points, point0) self.assertEqual(index0, 0) assert_almost_equal(ratio0, 0.0) point0_5 = calculate_position(ecef_points, 0, 0.5) index0_5, ratio0_5 = find_index_and_ratio(ecef_points, point0_5) self.assertEqual(index0_5, 0) assert_almost_equal(ratio0_5, 0.5) point0_99 = calculate_position(ecef_points, 0, 0.99) index0_99, ratio0_99 = find_index_and_ratio(ecef_points, point0_99) self.assertEqual(index0_99, 0) assert_almost_equal(ratio0_99, 0.99) point1 = ecef_points[1] index1, ratio1 = find_index_and_ratio(ecef_points, point1) self.assertEqual(index1, 1) assert_almost_equal(ratio1, 0.0) point1_01 = calculate_position(ecef_points, 1, 0.01) index1_01, ratio1_01 = find_index_and_ratio(ecef_points, point1_01) self.assertEqual(index1_01, 1) assert_almost_equal(ratio1_01, 0.01) point5 = calculate_position(ecef_points, 5) index5, ratio5 = find_index_and_ratio(ecef_points, point5) self.assertEqual(index5, 5) assert_almost_equal(ratio5, 0.0) point7_5 = calculate_position(ecef_points, 7, 0.5) index7_5, ratio7_5 = find_index_and_ratio(ecef_points, point7_5) self.assertEqual(index7_5, 7) assert_almost_equal(ratio7_5, 0.5) point10_99 = calculate_position(ecef_points, 10, 0.99) index10_99, ratio10_99 = find_index_and_ratio(ecef_points, point10_99) self.assertEqual(index10_99, 10) assert_almost_equal(ratio10_99, 0.99) point11 = ecef_points[11] index11, ratio11 = find_index_and_ratio(ecef_points, point11) self.assertEqual(index11, 11) assert_almost_equal(ratio11, 0.0)
def find_trajectory_user_airspace_intersections(smooth_traj): """ Find airspace user airspace intersection positions from a smoothed trajectory. Parameters ---------- smooth_traj: SmoothedTrajectory A SmoothedTrajectory containing the flight id, smoothed horizontal path, time profile and altitude profile. Returns ------- intersection_positions: a pandas DataFrame The trajectory user airspace intersection positions. Empty if no intersections found. """ lats = [] lons = [] volume_ids = [] min_altitude = smooth_traj.altp.altitudes.min() max_altitude = smooth_traj.altp.altitudes.max() lats, lons, volume_ids = find_horizontal_user_airspace_intersections( smooth_traj.flight_id, smooth_traj.path.lats, smooth_traj.path.lons, min_altitude, max_altitude) if len(lats): # A dict to hold the intersected volumes volumes = {} try: for volume_id in set(volume_ids): volume_name = get_user_sector_name(volume_id) bottom_alt, top_alt = get_user_sector_altitude_range(volume_id) volumes.setdefault( volume_id, AirspaceVolume(volume_name, bottom_alt, top_alt)) except NotFoundException: log.exception('user airspace id: %s not found for flight id: %s', volume_id, smooth_traj.flight_id) return pd.DataFrame() traj_path = smooth_traj.path.ecef_path() intersection_points = global_Point3d(np.array(lats), np.array(lons)) return find_3D_airspace_intersections(smooth_traj, traj_path, intersection_points, volume_ids, volumes) else: return pd.DataFrame()
def test_find_3D_airspace_intersections(self): path_0 = HorizontalPath(ROUTE_LATS, ROUTE_LONS, TURN_DISTANCES) timep_0 = TimeProfile(START_TIME, DISTANCES, ELAPSED_TIMES) altp_0 = ALTITUDE_PROFILE traj_0 = SmoothedTrajectory('123-456-789', path_0, timep_0, altp_0) LATS = np.array([0., 20. / 60., 40. / 60., 60. / 60.]) LONS = np.zeros(4, dtype=float) sector_ids = ['1', '2', '3', '1'] points_0 = global_Point3d(LATS, LONS) df_3d = find_3D_airspace_intersections(traj_0, path_0.ecef_path(), points_0, sector_ids, SECTORS) self.assertEqual(df_3d.shape[0], 6)
def test_SpherePath_calculate_ground_track(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) track_0 = ecef_path.calculate_ground_track(0, 0.0) assert_almost_equal(track_0, np.pi / 2, decimal=3) # close to due East track_2_5 = ecef_path.calculate_ground_track(2, 0.5) assert_almost_equal(track_2_5, np.pi) # due south track_2_0 = ecef_path.calculate_ground_track(2, 0.0) assert_almost_equal(track_2_0, 0.75 * np.pi, decimal=3) # South East track_12_0 = ecef_path.calculate_ground_track(12, 0.0) assert_almost_equal(track_12_0, 0.0) # North
def test_calculate_turn_initiation_distance_90(self): # A 90 degree turn at the Equator LATS = np.array([0.0, 0.0, 1.0]) LONS = np.array([1.0, 0.0, 0.0]) ecef_points = global_Point3d(LATS, LONS) prev_arc = Arc3d(ecef_points[0], ecef_points[1]) arc = Arc3d(ecef_points[1], ecef_points[2]) TEN_NM = TWENTY_NM / 2 turn_0 = SphereTurnArc(prev_arc, arc, TEN_NM) turn_angle_0 = turn_0.angle distance_start = calculate_turn_initiation_distance( prev_arc, arc, turn_0.start, TWENTY_NM, ACROSS_TRACK_TOLERANCE) assert_almost_equal(distance_start, TEN_NM) distance_finish = calculate_turn_initiation_distance( prev_arc, arc, turn_0.finish, TWENTY_NM, ACROSS_TRACK_TOLERANCE) assert_almost_equal(distance_finish, TEN_NM) point_1 = turn_0.position(turn_angle_0 / 2) distance_1 = calculate_turn_initiation_distance( prev_arc, arc, point_1, TWENTY_NM, ACROSS_TRACK_TOLERANCE) assert_almost_equal(distance_1, TEN_NM) point_2 = turn_0.position(turn_angle_0 / 4) distance_2 = calculate_turn_initiation_distance( prev_arc, arc, point_2, TWENTY_NM, ACROSS_TRACK_TOLERANCE) assert_almost_equal(distance_2, TEN_NM) point_3 = turn_0.position(3 * turn_angle_0 / 4) distance_3 = calculate_turn_initiation_distance( prev_arc, arc, point_3, TWENTY_NM, ACROSS_TRACK_TOLERANCE) assert_almost_equal(distance_3, TEN_NM) # Test with a point further than TWENTY_NM from the intersection turn_30 = SphereTurnArc(prev_arc, arc, TWENTY_NM + TEN_NM) distance_4 = calculate_turn_initiation_distance( prev_arc, arc, turn_30.start, TWENTY_NM, ACROSS_TRACK_TOLERANCE) self.assertEqual(distance_4, TWENTY_NM) point_30 = turn_30.position(3 * turn_angle_0 / 4) distance_30 = calculate_turn_initiation_distance( prev_arc, arc, point_30, TWENTY_NM, ACROSS_TRACK_TOLERANCE) self.assertEqual(distance_30, TWENTY_NM)
def test_calculate_2D_intersection_distances(self): path_0 = HorizontalPath(ROUTE_LATS, ROUTE_LONS, TURN_DISTANCES) LATS = np.array([20. / 60., 40. / 60., 60. / 60.]) LONS = np.zeros(3, dtype=float) intersection_points = global_Point3d(LATS, LONS) sector_ids = ['2', '3', '1'] start_distance = 0. distances_1 = calculate_2D_intersection_distances( path_0.ecef_path(), intersection_points, sector_ids, start_distance) self.assertEqual(len(distances_1), 3) start_distance = 20. distances_2 = calculate_2D_intersection_distances( path_0.ecef_path(), intersection_points, sector_ids, start_distance) self.assertEqual(len(distances_2), 3)
def test_SpherePath_calculate_positions(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) ecef_path = SpherePath(ecef_points, TURN_DISTANCES) distances, types = ecef_path.section_distances_and_types() positions = ecef_path.calculate_positions(distances) self.assertEqual(len(positions), len(ecef_path) + 8) assert_almost_equal(distance_radians(positions[0], ecef_points[0]), 0.0) assert_almost_equal(distance_radians(positions[1], ecef_points[1]), 0.0) assert_almost_equal(distance_radians(positions[-2], ecef_points[-2]), 0.0) assert_almost_equal(distance_radians(positions[-1], ecef_points[-1]), 0.0)
def test_calculate_intersection(self): ecef_points = global_Point3d(ROUTE_LATS, ROUTE_LONS) # intersection point between arcs on different Great Circles prev_arc = Arc3d(ecef_points[0], ecef_points[1]) arc = Arc3d(ecef_points[1], ecef_points[2]) point_1 = calculate_intersection(prev_arc, arc) assert_almost_equal(distance_radians(point_1, ecef_points[1]), 0.0) # intersection point between arcs on same Great Circles next_point = arc.position(2 * arc.length()) next_arc = Arc3d(ecef_points[2], next_point) point_2 = calculate_intersection(arc, next_arc) assert_almost_equal(distance_radians(point_2, ecef_points[2]), 0.0) # intersection point between arcs on different Great Circles, # opposite direction turn prev_arc = Arc3d(ecef_points[5], ecef_points[6]) arc = Arc3d(ecef_points[6], ecef_points[7]) point_3 = calculate_intersection(prev_arc, arc) assert_almost_equal(distance_radians(point_3, ecef_points[6]), 0.0)
def test_find_3D_airspace_no_intersections(self): path_0 = HorizontalPath(ROUTE_LATS, ROUTE_LONS, TURN_DISTANCES) timep_0 = TimeProfile(START_TIME, DISTANCES, ELAPSED_TIMES) # Create a altitude profile above the sectors HIGH_ALTITUDES = np.array([ 10000., 11800., 13000., 13600., 14200., 15400., 16000., 16000., 16000., 16000., 15400., 14200. ]) alt_p = AltitudeProfile(DISTANCES, HIGH_ALTITUDES) traj_0 = SmoothedTrajectory('123-456-789', path_0, timep_0, alt_p) LATS = np.array([0., 20. / 60., 40. / 60., 60. / 60.]) LONS = np.zeros(4, dtype=float) sector_ids = ['1', '2', '3', '1'] points_0 = global_Point3d(LATS, LONS) df_3d = find_3D_airspace_intersections(traj_0, path_0.ecef_path(), points_0, sector_ids, SECTORS) self.assertEqual(df_3d.shape[0], 0)
def test_calculate_position(self): ecef_points = global_Point3d(PANDAS_ICOSAHEDRON['LAT'], PANDAS_ICOSAHEDRON['LON']) point_0 = calculate_position(ecef_points, 0) assert_almost_equal(distance_radians(point_0, ecef_points[0]), 0.0) point_11 = calculate_position(ecef_points, 11) assert_almost_equal(distance_radians(point_11, ecef_points[-1]), 0.0) point_11_5 = calculate_position(ecef_points, 11, ratio=0.5) assert_almost_equal(distance_radians(point_11_5, ecef_points[-1]), 0.0) point_5_5 = calculate_position(ecef_points, 5, ratio=0.5) assert_almost_equal(distance_radians(point_5_5, ecef_points[5]), 0.5 * GOLDEN_ANGLE) assert_almost_equal(distance_radians(point_5_5, ecef_points[6]), 0.5 * GOLDEN_ANGLE) point_7_25 = calculate_position(ecef_points, 7, ratio=0.25) assert_almost_equal(distance_radians(point_7_25, ecef_points[7]), 0.25 * GOLDEN_ANGLE) assert_almost_equal(distance_radians(point_7_25, ecef_points[8]), 0.75 * GOLDEN_ANGLE)