def full_transit_arrows_with_position_error( arrow_rgb: str, error: typing.Union[int, float], line_width: float) -> typing.List[str]: """ Returns a list of gnuplot directives that are lines between the from/to full transit points with the given positional error. """ ret = [] observer = video_utils.XY(*observer_xy()) for transit_line in video_data.GOOGLE_EARTH_FULL_TRANSITS: new_from, new_to, new_bearing = video_utils.transit_point_with_error( transit_line.frm.xy, transit_line.to.xy, error=error) end_point = video_utils.transit_line_past_observer( new_from, new_to, observer, 250.0) ret.append( 'set arrow from {x0:.0f},{y0:.0f} to {x1:.0f},{y1:.0f} nohead lw {lw:0.2f} lc rgb "{arrow_rgb}" dt 4' .format( x0=new_from.x, y0=new_from.y, x1=end_point.x, y1=end_point.y, arrow_rgb=arrow_rgb, lw=line_width, )) return ret
def create_svg_transit_to_observer_xy() -> typing.List[str]: """ Returns a list of SVG strings for the transit lines to the estimated observer position. """ result = [] # TODO: Have a common API for observer postion observer_xy_array, _possible = video_analysis.observer_position_combinations_from_aspects( baseline=plot_constants.OBSERVER_XY_MINIMUM_BASELINE, ignore_first_n=plot_constants.OBSERVER_XY_IGNORE_N_FIRST_BEARINGS, ) observer_xy = video_utils.XY( np.mean(observer_xy_array[:, 0]) + plot_common.x_offset(), np.mean(observer_xy_array[:, 1])) result.append('<!-- {} -->'.format( 'create_svg_transit_to_observer_xy()'.center(75))) colour = 'black' radius = plot_constants.distance_m_to_pixels(15) for transit_line in video_data.GOOGLE_EARTH_FULL_TRANSITS: x_0, y_0 = transit_line.frm.xy circle_pos_0 = plot_constants.position_m_to_pixels( plot_constants.PosXY(x_0, y_0)) result.append( '<circle cx="{cx:.1f}" cy="{cy:.1f}" r="{r:.1f}" stroke="{colour:}" stroke-width="1" fill="none" />' .format( colour=colour, cx=circle_pos_0.x, cy=circle_pos_0.y, r=radius, )) x_1, y_1 = transit_line.to.xy circle_pos_1 = plot_constants.position_m_to_pixels( plot_constants.PosXY(x_1, y_1)) result.append( '<circle cx="{cx:.1f}" cy="{cy:.1f}" r="{r:.1f}" stroke="{colour:}" stroke-width="1" fill="none" />' .format( colour=colour, cx=circle_pos_1.x, cy=circle_pos_1.y, r=radius, )) end_point = video_utils.transit_line_past_observer( transit_line.frm.xy, transit_line.to.xy, observer_xy, 250.0) # print('TRACE: create_svg_transit_to_observer_xy():', end_point) circle_pos_2 = plot_constants.position_m_to_pixels(end_point) result.append( '<line x1="{x1:.1f}" y1="{y1:.1f}" x2="{x2:.1f}" y2="{y2:.1f}" stroke="{colour:}" stroke-width="1" />' .format( colour=colour, x1=circle_pos_0.x, y1=circle_pos_0.y, x2=circle_pos_2.x, y2=circle_pos_2.y, )) result.append('<!-- DONE {} -->'.format( 'create_svg_transit_to_observer_xy()'.center(75))) return result
def markdown_table_distance_from_start_by_transit( ) -> typing.Tuple[typing.List[str], str]: result = [ '| Video Time (mm:ss:ff) | Distance from Start of Runway (m) |', '| --- | ---: |', ] observer_xy_start_runway = video_utils.XY(*plot_common.observer_xy()) for transit_line in video_data.GOOGLE_EARTH_FULL_TRANSITS: x_intercept = video_utils.transit_x_axis_intercept( transit_line.frm.xy.x, transit_line.frm.xy.y, *observer_xy_start_runway) result.append('| {:02d}:{:02d}:{:02d} | {x_runway:.0f} |'.format( transit_line.time.min, transit_line.time.sec, transit_line.time.frame, x_runway=x_intercept, )) return result, 'Aircraft Position from Runway Start from Full Transits'
def full_transit_labels_and_arrows(arrow_rgb: str, line_width: float) -> typing.List[str]: """ Returns a list of gnuplot directives that are lines between the from/to full transit points and labels the from/to points. """ ret = [] observer = video_utils.XY(*observer_xy()) for transit_line in video_data.GOOGLE_EARTH_FULL_TRANSITS: # Compute a position past the observer end_point = video_utils.transit_line_past_observer( transit_line.frm.xy, transit_line.to.xy, observer, 250.0) # Line between from/to points ret.append( 'set arrow from {x0:.0f},{y0:.0f} to {x1:.0f},{y1:.0f} nohead lw {lw:0.2f} lc rgb "{arrow_rgb}"' .format( x0=transit_line.frm.xy.x, y0=transit_line.frm.xy.y, x1=end_point.x, y1=end_point.y, arrow_rgb=arrow_rgb, lw=line_width, )) # Label from point ret.append( 'set label "{label:}" at {x:.1f},{y:.1f} right font ",9" rotate by -30' .format( label=transit_line.frm.label, x=transit_line.frm.xy.x - 50, y=transit_line.frm.xy.y, )) # Label to point ret.append( 'set label "{label:}" at {x:.1f},{y:.1f} right font ",9" rotate by -30' .format( label=transit_line.to.label, x=transit_line.to.xy.x - 50, y=transit_line.to.xy.y, )) return ret
def gnuplot_full_transits( stream: typing.TextIO = sys.stdout) -> typing.List[str]: result = ['# "{}"'.format('Full transit lines.')] notes = ['time x(m) y(m) x(y=0)(m) y==0(m) Name'] if len(notes): stream.write('#\n') stream.write('# Notes:\n') for note in notes: stream.write('# {}\n'.format(note)) observer_xy_start_runway = video_utils.XY(*plot_common.observer_xy()) # Y range 2000m is 800px so a 50m wide runway would be 800 * 50 / 2000 = 20px computed_data = [ 'set arrow from {x0:.0f},{y0:.0f} to {x1:.0f},{y1:.0f} nohead lw 20 lc rgb "#C0C0C0" back' .format( x0=0.0, y0=0.0, x1=3240, y1=0, ) ] for transit_line in video_data.GOOGLE_EARTH_FULL_TRANSITS: x_intercept = video_utils.transit_x_axis_intercept( transit_line.frm.xy.x, transit_line.frm.xy.y, *observer_xy_start_runway) stream.write( '{t:<6.1f} {x:6.1f} {y:6.1f} {x_runway:6.1f} 0.0 # {label:}\n'. format(t=transit_line.time.time, x=transit_line.frm.xy.x, y=transit_line.frm.xy.y, x_runway=x_intercept, label='{}->{}'.format(transit_line.frm.label, transit_line.to.label))) stream.write( '{t:<6.1f} {x:6.1f} {y:6.1f} {x_runway:6.1f} 0.0 # {label:}\n'. format(t=transit_line.time.time, x=transit_line.to.xy.x, y=transit_line.to.xy.y, x_runway=x_intercept, label='{}->{}'.format(transit_line.frm.label, transit_line.to.label))) computed_data.append( 'set label "t={t:.1f}s x={x_runway:.0f}m" at {x:.0f},{y:.0f} right font ",9" textcolor rgb "#007F00" rotate by -30 front' .format( t=transit_line.time.time, x_runway=x_intercept, x=x_intercept - 20, y=0 + -20, )) computed_data.extend( plot_common.full_transit_labels_and_arrows('#0000FF', 0.75)) # # Apply positional error and plot # # 808080 # computed_data.extend( # plot_common.full_transit_arrows_with_position_error( # '#FF0000', video_data.GOOGLE_EARTH_ERROR, 0.5 # ) # ) # computed_data.extend( # plot_common.full_transit_arrows_with_position_error( # '#0000FF', -video_data.GOOGLE_EARTH_ERROR, 0.5 # ) # ) # Label and arrow to observers position observer_x_mean, observer_x_diff, observer_y_mean, observer_y_diff = plot_common.observer_position_from_full_transits( ) computed_data.extend([ 'set label "X={x_mean:.0f} ±{x_err:.0f}m Y={y_mean:.0f} ±{y_err:.0f} m" at {x:.0f},{y:.0f} right font ",12"' .format( x_mean=observer_x_mean, x_err=observer_x_diff, y_mean=observer_y_mean, y_err=observer_y_diff, x=observer_x_mean - 510, y=observer_y_mean - 110, ), 'set arrow from {:.0f},{:.0f} to {:.0f},{:.0f} lt -1 lw 2 empty'. format( observer_x_mean - 500, observer_y_mean - 100, observer_x_mean, observer_y_mean, ), ]) return computed_data
def test_intersect_two_lines(x00, y00, x01, y01, x10, y10, x11, y11, expected): result = video_utils.intersect_two_lines( video_utils.XY(x00, y00), video_utils.XY(x01, y01), video_utils.XY(x10, y10), video_utils.XY(x11, y11), ) assert expected == result
(0.0, 330.0, math.cos(math.radians(30)), 270.0, math.cos(math.radians(30)), -0.5), ), ) def test_aspect_intersection(d0, b0, d1, b1, expected_d, expected_y): d, y = video_utils.aspect_intersection(d0, b0, d1, b1) assert math.isclose(expected_d, d) assert math.isclose(expected_y, y) @pytest.mark.parametrize( 'x00, y00, x01, y01, x10, y10, x11, y11, expected', ( ( 0, 0, 1, 1, 0, 1, 1, 1, video_utils.XY(1, 1), ), ( 0, 0, 2, 2, 8, 0, 6, 2, video_utils.XY(4, 4), ), # # Full transit from Tower 8 to Concrete block hut : (125.279980944823, 707.8758276857575) (2146.0969961863984, -231.2907541223004) # # Full transit from Trees right of Fedex to Factory interior corner: (2452.9657502621976, 384.50753297703915) (3178.040481477931, -356.6795624918748) # # Full transit from Tall radio tower to Building corner : (3032.1063544106087, 814.9559001880468) (3274.3474416526055, -140.67283110970288) # # # Full transit from Tower 8 to Concrete block hut : (125.279980944823, 707.8758276857575) (2146.0969961863984, -231.2907541223004) # # Full transit from Trees right of Fedex to Factory interior corner: (2729.62631272838, 383.37932910566354) (3178.040481477931, -356.6795624918748) # # Full transit from Tall radio tower to Building corner : (3032.1063544106087, 814.9559001880468) (3274.3474416526055, -140.67283110970288) # ( # # Tower 8 to Concrete block hut
# pprint.pprint(GOOGLE_EARTH_TOWER_POSITIONS_XY) for r, row in enumerate(GOOGLE_EARTH_TOWER_POSITIONS_XY): prev = None for c, col in enumerate(row): if prev is not None: print('[{:d}, {:d}]: {:10.1f}, {:10.1f} {:+10.3f}, {:+10.3f}'. format(r, c, col[0], col[1], col[0] - prev[0], col[1] - prev[1])) else: print('[{:d}, {:d}]: {:10.1f}, {:10.1f}'.format(r, c, *col)) prev = col print() # TODO: Use plot_common.x_offset() rather than 1182 OBSERVER_XY_START_RUNWAY_BEARINGS = video_utils.XY(2266 + 1182, -763) OBSERVER_XY_START_RUNWAY_FULL_TRANSITS = video_utils.XY(3433.785, -774.615) def print_transits_and_runway_distances(): speed = 0.0 prev = (0.0, 0.0, 0.0) # Google earth print('Transits for observer at:', OBSERVER_XY_START_RUNWAY_FULL_TRANSITS) fw = max([len(k) for _t, k in GOOGLE_EARTH_EVENTS]) for t, k in GOOGLE_EARTH_EVENTS: event_time = GOOGLE_EARTH_EVENT_MAP[k] # print(event, lat, lon) # print('lat, lon', k, lat, lon) x, y = video_utils.lat_long_to_xy( GOOGLE_EARTH_DATUM_LAT_LONG,