def print_events_on_GoogleEarth_C_Annotated() -> None: print('print_events_on_GoogleEarth_C_Annotated():') # File: GoogleEarth_C_Annotated.png runway_23_start = map_funcs.Point(687, 44) runway_23_end = map_funcs.Point(285, 556) m_per_px = google_earth.RUNWAY_LENGTH_M / map_funcs.distance_between_points( runway_23_start, runway_23_end) tile_d_fits = get_tile_d_fits()[1] slab_v_fits = get_slab_v_fits() for frame_number in sorted(FRAME_EVENTS.keys()): d, _d_plus, _d_minus = _compute_distance(frame_number, tile_d_fits, slab_v_fits) d_px = d / m_per_px new_pt = map_funcs.point_translate(runway_23_start, google_earth.RUNWAY_HEADING_DEG, d_px) # print(frame_number, d, d_px, new_pt) print( f'{frame_number:4d} {d:8.0f} {d_px:8.1f} x={new_pt.x:6.1f} y={new_pt.y:6.1f} {FRAME_EVENTS[frame_number]}' ) name_pt_xy = google_earth.measurements_relative_to_runway() for name in name_pt_xy: x_px = name_pt_xy[name].x / m_per_px new_pt = map_funcs.point_translate(runway_23_start, google_earth.RUNWAY_HEADING_DEG, x_px) # print(frame_number, d, d_px, new_pt) print( f'{name_pt_xy[name].x:8.0f} {x_px:8.1f} x={new_pt.x:6.1f} y={new_pt.y:6.1f} {name}' )
def xy_from_range_bearing(range: float, bearing: float) -> map_funcs.Point: """Given a range in metres and a bearing from the camera this returns the x, y position in metres relative to the runway start.""" theta_deg = bearing - google_earth.RUNWAY_HEADING_DEG x = CAMERA_POSITION_XY.x + range * math.cos(math.radians(theta_deg)) y = CAMERA_POSITION_XY.y + range * math.sin(math.radians(theta_deg)) return map_funcs.Point(x, y)
# Impact site is tile 7, Point(926, 737) # Impact at 00:57. # In metres # DISTANCE_FROM_RUNWAY_END_TO_FENCE = 213.0 # DISTANCE_FROM_FENCE_TO_FINAL_IMPACT = 38.4 # DISTANCE_FROM_RUNWAY_END_TO_FINAL_IMPACT = DISTANCE_FROM_RUNWAY_END_TO_FENCE + DISTANCE_FROM_FENCE_TO_FINAL_IMPACT FRAME_THRESHOLD = 827 FRAME_TOUCHDOWN = 1015 # Movement of camera due to impact. FRAME_LAST = 1819 POSITIONS_FROM_TILES: typing.Dict[int, typing.Tuple[ int, map_funcs.Point, str]] = { 1: (1, map_funcs.Point(1207, 749), 'Edge of settlement in line with dark patch on island in the foreground.' ), 87: (1, map_funcs.Point(939, 1087), 'Settlement line with isolated lake and finger into lake.'), 295: (2, map_funcs.Point(1164, 801), 'Trees and edge of V shaped lake.'), 483: (3, map_funcs.Point(1258, 627), 'Blue roofed building in line with RHS of larger white building.'), 555: (3, map_funcs.Point(1040, 903), 'Factory with covered conveyer belt.'), 593: (3, map_funcs.Point(938, 1033), 'Tree line with red building behind.'), 621: (3, map_funcs.Point(840, 1159), 'Blue building left lined up with low white building left.'),
3: 'https://www.google.com/maps/@55.8138262,109.6138347,831m/data=!3m1!1e3', 4: 'https://www.google.com/maps/@55.8088004,109.6072157,835m/data=!3m1!1e3', 5: 'https://www.google.com/maps/@55.8040851,109.6001154,834m/data=!3m1!1e3', 6: 'https://www.google.com/maps/@55.798493,109.5920735,830m/data=!3m1!1e3', 7: 'https://www.google.com/maps/@55.7943906,109.5867373,827m/data=!3m1!1e3', } TILE_WIDTH = 2560 TILE_HEIGHT = 1440 TILE_SCALE_M_PER_PIXEL = 50.0 / (2536 - 2455) TILE_TIE_POINTS = { # Brown pixel on SE edge of red roofed house. (1, 2): (map_funcs.Point(141, 1217), map_funcs.Point(952, 179)), # SE point of jetty (?) (2, 3): (map_funcs.Point(532, 1171), map_funcs.Point(1220, 239)), # Centre of white mark (3, 4): (map_funcs.Point(1189, 1212), map_funcs.Point(1854, 312)), # NW tip of threshold i.e. RHS on approach (4, 5): (map_funcs.Point(856, 1034), map_funcs.Point(1577, 182)), # NE tip of threshold i.e. LHS on approach # # These might be a few pixels to the south east because of glare. # (4, 5): (map_funcs.Point(907, 1074), map_funcs.Point(1627, 222)), # South tip of pin identifying airport (5, 6): (map_funcs.Point(1137, 1254), map_funcs.Point(1952, 245)), # South tip of pin identifying supermarket (6, 7): (map_funcs.Point(1120, 1118), map_funcs.Point(1663, 375)), }
import pytest import map_data import map_funcs @pytest.mark.parametrize( 'tile_a, point_a, tile_b, expected', ( # Threshold in x/y of tile 3 of other tiles (3, map_data.RUNWAY_23_THRESHOLD_TILE_3, 1, map_funcs.Point(-431, 2282)), (3, map_data.RUNWAY_23_THRESHOLD_TILE_3, 2, map_funcs.Point(476, 1434)), (3, map_data.RUNWAY_23_THRESHOLD_TILE_3, 4, map_funcs.Point(2250, -318)), (3, map_data.RUNWAY_23_THRESHOLD_TILE_3, 5, map_funcs.Point(2678, -1052)), ) ) def test_point_tile_to_tile(tile_a, point_a, tile_b, expected): result = map_funcs.point_tile_to_tile(tile_a, point_a, tile_b) assert result == expected @pytest.mark.parametrize( 'tile_a, point_a, tile_b, point_b, expected', ( (3, map_data.RUNWAY_23_THRESHOLD_TILE_3, 3, map_data.RUNWAY_23_THRESHOLD_TILE_3, map_funcs.Distance(0, 0)), (1, map_funcs.Point(566, 1091), 2, map_funcs.Point(1473, 243), map_funcs.Distance(0, 0)), (2, map_funcs.Point(1473, 243), 1, map_funcs.Point(566, 1091), map_funcs.Distance(0, 0)), (2, map_funcs.Point(1212, 1202), 3, map_funcs.Point(1508, 350), map_funcs.Distance(0, 0)), (3, map_funcs.Point(1508, 350), 2, map_funcs.Point(1212, 1202), map_funcs.Distance(0, 0)),
'Increase in tyre smoke', 290: 'Start of large dust plume', # This is estimated as 1 second before the black smoke starts appearing 23 * FRAME_RATE + 1: 'Start of smoke plume' } FRAME_EVENTS_STR_KEY = {v: k for k, v in FRAME_EVENTS.items()} # In frame 850 these are the positions of objects observable on google earth FRAME_850_POSITIONS: typing.Dict[str, map_funcs.Point] = { # Dark smudge on right # 'right_dark_grass': map_funcs.Point(625, 173), # Pale smudge on right where tarmac meets grass 'right_light_grass': map_funcs.Point(485, 164), # Pale smudge on left where tarmac taxiway meets grass # 'left_light_grass': map_funcs.Point(32, 112), # Bright roofed house, slightly dubious connection. 'bright_roofed_house': map_funcs.Point(277, 75), # Mi-2 helicopter 'helicopter': map_funcs.Point(356, 111), # Some structures on the extreme left 'buildings_apron_edge': map_funcs.Point(12, 101), # Estimated from the base of the dark smoke column. 'red_building': map_funcs.Point(75, 90), } FRAME_850_HELICOPTER_HEIGHT_PIXELS = 30 FRAME_850_HELICOPTER_LENGTH_PIXELS = 68 FRAME_850_ERROR_PIXELS = 2