Ejemplo n.º 1
0
def calculate_time_points_reduction(t):
    from pilot.flightresult import FlightResult
    p = FlightResult()
    p.distance_flown = t.opt_dist
    p.SSS_time = t.max_ss_time
    p.ESS_time = t.stop_time
    return pilot_speed(t, p)
Ejemplo n.º 2
0
def evaluate_goal(result: FlightResult, task: Task):
    """ ?p:p?PilotsLandingBeforeGoal:bestDistancep = max(minimumDistance, taskDistance-min(?trackp.pointi shortestDistanceToGoal(trackp.pointi)))
        ?p:p?PilotsReachingGoal:bestDistancep = taskDistance
    """
    if any(e.name == 'Goal' for e in result.waypoints_achieved):
        result.distance_flown = task.opt_dist
        result.goal_time, result.goal_altitude = min(
            [(x.rawtime, x.altitude)
             for x in result.waypoints_achieved if x.name == 'Goal'],
            key=lambda t: t[0])
        result.result_type = 'goal'
Ejemplo n.º 3
0
def calculate_min_dist_score(t):
    from pilot.flightresult import FlightResult
    p = FlightResult()
    p.distance_flown = t.formula.min_dist
    return pilot_distance(t, p)
Ejemplo n.º 4
0
def check_fixes(result: FlightResult,
                fixes: list,
                task: Task,
                tp: FlightPointer,
                lead_coeff: LeadCoeff = None,
                airspace: AirspaceCheck = None,
                livetracking: bool = False,
                igc_parsing_config: FlightParsingConfig = None,
                deadline: int = None,
                print=print):
    """"""
    '''initialize'''
    total_fixes = len(fixes)
    tolerance = task.formula.tolerance or 0
    min_tol_m = task.formula.min_tolerance or 0
    max_jump_the_gun = task.formula.max_JTG or 0  # seconds
    jtg_penalty_per_sec = 0 if max_jump_the_gun == 0 else task.formula.JTG_penalty_per_sec
    distances2go = task.distances_to_go  # Total task Opt. Distance, in legs list
    ''' Altitude Source: '''
    alt_source = 'GPS' if task.formula.scoring_altitude is None else task.formula.scoring_altitude
    alt_compensation = 0 if alt_source == 'GPS' or task.QNH == 1013.25 else task.alt_compensation
    '''Stopped task managing'''
    if task.stopped_time:
        if not deadline:
            '''Using stop_time (stopped_time - score_back_time)'''
            deadline = task.stop_time
        goal_altitude = task.goal_altitude or 0
        glide_ratio = task.formula.glide_bonus or 0
        stopped_distance = 0
        stopped_altitude = 0
        total_distance = 0

    if not livetracking:
        percentage_complete = 0
    else:
        '''get if pilot already started in previous track slices'''
        already_started = tp.start_done
        '''get if pilot already made ESS in previous track slices'''
        already_ESS = any(e.name == 'ESS' for e in result.waypoints_achieved)

    for i in range(total_fixes - 1):
        # report percentage progress
        if not livetracking and int(
                i / len(fixes) * 100) > percentage_complete:
            percentage_complete = int(i / len(fixes) * 100)
            print(f"{percentage_complete}|% complete")
        '''Get two consecutive trackpoints as needed to use FAI / CIVL rules logic
        '''
        # start_time = tt.time()
        my_fix = fixes[i]
        next_fix = fixes[i + 1]
        if livetracking:
            alt = next_fix.alt
            '''check coherence'''
            if next_fix.rawtime - my_fix.rawtime < 1:
                continue
            alt_rate = abs(next_fix.alt - my_fix.alt) / (next_fix.rawtime -
                                                         my_fix.rawtime)
            if (alt_rate > igc_parsing_config.max_alt_change_rate
                    or not igc_parsing_config.min_alt < alt <
                    igc_parsing_config.max_alt):
                continue
            '''check flying'''
            speed = next_fix.speed  # km/h
            if not result.first_time:
                '''not launched yet'''
                launch = next(x for x in tp.turnpoints if x.type == 'launch')
                if (abs(launch.altitude - alt) >
                        igc_parsing_config.min_alt_difference
                        and speed > igc_parsing_config.min_gsp_flight):
                    '''pilot launched'''
                    result.first_time = next_fix.rawtime
                    result.live_comment = 'flying'
                else:
                    '''still on launch'''
                    continue

            else:
                '''check if pilot landed'''
                if speed < igc_parsing_config.min_gsp_flight:
                    if not result.suspect_landing_fix:
                        result.suspect_landing_fix = next_fix
                        # suspect_landing_alt = alt
                    else:
                        time_diff = next_fix.rawtime - result.suspect_landing_fix.rawtime
                        alt_diff = abs(alt - result.suspect_landing_fix.alt)
                        if (time_diff > igc_parsing_config.max_still_seconds
                                and alt_diff <
                                igc_parsing_config.min_alt_difference):
                            '''assuming pilot landed'''
                            result.landing_time = next_fix.rawtime
                            result.landing_altitude = alt
                            result.live_comment = 'landed'
                            break
                elif result.suspect_landing_fix is not None:
                    result.suspect_landing_fix = None
        else:
            alt = next_fix.gnss_alt if alt_source == 'GPS' else next_fix.press_alt + alt_compensation

            if next_fix.rawtime < result.first_time:
                '''skip'''
                continue
            if result.landing_time and next_fix.rawtime > result.landing_time:
                '''pilot landed out'''
                # print(f'fix {i}: landed out - {next_fix.rawtime} - {alt}')
                break
        '''max altitude'''
        if alt > result.max_altitude:
            result.max_altitude = alt
        '''handle stopped task
        Pilots who were at a position between ESS and goal at the task stop time will be scored for their 
        complete flight, including the portion flown after the task stop time. 
        This is to remove any discontinuity between pilots just before goal and pilots who had just reached goal 
        at task stop time.
        '''
        if task.stopped_time and next_fix.rawtime > deadline and not tp.ess_done:
            result.still_flying_at_deadline = True
            result.stopped_distance = stopped_distance
            result.stopped_altitude = stopped_altitude
            result.total_distance = total_distance
            break
        '''check if task deadline has passed'''
        if task.task_deadline < next_fix.rawtime:
            # Task has ended
            result.still_flying_at_deadline = True
            break
        '''check if pilot has arrived in goal (last turnpoint) so we can stop.'''
        if tp.made_all:
            break
        '''check if start closing time passed and pilot did not start'''
        if task.start_close_time and task.start_close_time < my_fix.rawtime and not tp.start_done:
            # start closed
            break
        '''check tp type is known'''
        if tp.next.type not in ('launch', 'speed', 'waypoint', 'endspeed',
                                'goal'):
            assert False, f"Unknown turnpoint type: {tp.type}"
        '''check window is open'''
        if task.window_open_time > next_fix.rawtime:
            continue
        '''launch turnpoint managing'''
        if tp.type == "launch":
            if task.check_launch == 'on':
                # Set radius to check to 200m (in the task def it will be 0)
                # could set this in the DB or even formula if needed..???
                tp.next.radius = 200  # meters
                if tp.next.in_radius(my_fix, tolerance, min_tol_m):
                    result.waypoints_achieved.append(
                        create_waypoint_achieved(my_fix, tp, my_fix.rawtime,
                                                 alt))
                    tp.move_to_next()
            else:
                tp.move_to_next()

        # to do check for restarts for elapsed time tasks and those that allow jump the gun
        # if started and task.task_type != 'race' or result.jump_the_gun is not None:
        '''start turnpoint managing'''
        '''given all n crossings for a turnpoint cylinder, sorted in ascending order by their crossing time,
        the time when the cylinder was reached is determined.
        turnpoint[i] = SSS : reachingTime[i] = crossing[n].time
        turnpoint[i] =? SSS : reachingTime[i] = crossing[0].time

        We need to check start in 3 cases:
        - pilot has not started yet
        - race has multiple starts
        - task is elapsed time
        '''
        if pilot_can_start(task, tp, my_fix):
            # print(f'time: {my_fix.rawtime}, start: {task.start_time} | Interval: {task.SS_interval} | my start: {result.real_start_time} | better_start: {pilot_get_better_start(task, my_fix.rawtime, result.SSS_time)} | can start: {pilot_can_start(task, tp, my_fix)} can restart: {pilot_can_restart(task, tp, my_fix, result)} | tp: {tp.name}')
            if start_made_civl(my_fix, next_fix, tp.next, tolerance,
                               min_tol_m):
                time = int(round(tp_time_civl(my_fix, next_fix, tp.next), 0))
                result.waypoints_achieved.append(
                    create_waypoint_achieved(my_fix, tp, time,
                                             alt))  # pilot has started
                result.real_start_time = time
                if not livetracking:
                    print(
                        f"Pilot started SS at {sec_to_time(result.real_start_time)}"
                    )
                result.best_distance_time = time
                tp.move_to_next()

        elif pilot_can_restart(task, tp, my_fix, result):
            # print(f'time: {my_fix.rawtime}, start: {task.start_time} | Interval: {task.SS_interval} | my start: {result.real_start_time} | better_start: {pilot_get_better_start(task, my_fix.rawtime, result.SSS_time)} | can start: {pilot_can_start(task, tp, my_fix)} can restart: {pilot_can_restart(task, tp, my_fix, result)} | tp: {tp.name}')
            if start_made_civl(my_fix, next_fix, tp.last_made, tolerance,
                               min_tol_m):
                tp.pointer -= 1
                time = int(round(tp_time_civl(my_fix, next_fix, tp.next), 0))
                result.waypoints_achieved.pop()
                result.waypoints_achieved.append(
                    create_waypoint_achieved(my_fix, tp, time,
                                             alt))  # pilot has started again
                result.real_start_time = time
                result.best_distance_time = time
                if not livetracking:
                    print(
                        f"Pilot restarted SS at {sec_to_time(result.real_start_time)}"
                    )
                if lead_coeff:
                    lead_coeff.reset()
                tp.move_to_next()

        if tp.start_done:
            '''Turnpoint managing'''
            if (tp.next.shape == 'circle'
                    and tp.next.type in ('endspeed', 'waypoint')):
                if tp_made_civl(my_fix, next_fix, tp.next, tolerance,
                                min_tol_m):
                    time = int(
                        round(tp_time_civl(my_fix, next_fix, tp.next), 0))
                    result.waypoints_achieved.append(
                        create_waypoint_achieved(
                            my_fix, tp, time,
                            alt))  # pilot has achieved turnpoint
                    if not livetracking:
                        print(
                            f"Pilot took {tp.name} at {sec_to_time(time)} at {alt}m"
                        )
                    tp.move_to_next()

            if tp.ess_done and tp.type == 'goal':
                if ((tp.next.shape == 'circle' and tp_made_civl(
                        my_fix, next_fix, tp.next, tolerance, min_tol_m))
                        or (tp.next.shape == 'line' and
                            (in_goal_sector(task, next_fix)))):
                    result.waypoints_achieved.append(
                        create_waypoint_achieved(
                            next_fix, tp, next_fix.rawtime,
                            alt))  # pilot has achieved goal
                    result.best_distance_time = next_fix.rawtime
                    if not livetracking:
                        print(f"Goal at {sec_to_time(next_fix.rawtime)}")
                    tp.done()
                    break
        '''update result data
        Once launched, distance flown should be max result among:
        - previous value;
        - optimized dist. to last turnpoint made;
        - total optimized distance minus opt. distance from next wpt to goal minus dist. to next wpt;
        '''
        if tp.pointer > 0:
            if tp.start_done and not tp.ess_done:
                '''optimized distance calculation each fix'''
                fix_dist_flown = task.opt_dist - get_shortest_path(
                    task, next_fix, tp.pointer)
                # print(f'time: {next_fix.rawtime} | fix: {tp.name} | Optimized Distance used')
            else:
                '''simplified and faster distance calculation'''
                fix_dist_flown = distance_flown(next_fix, tp.pointer,
                                                task.optimised_turnpoints,
                                                task.turnpoints[tp.pointer],
                                                distances2go)
                # print(f'time: {next_fix.rawtime} | fix: {tp.name} | Simplified Distance used')

            if fix_dist_flown > result.distance_flown:
                '''time of trackpoint with shortest distance to ESS'''
                result.best_distance_time = next_fix.rawtime
                '''updating best distance flown'''
                result.distance_flown = fix_dist_flown
            '''stopped task
            ∀p : p ∈ PilotsLandedBeforeGoal :
                bestDistance p = max(minimumDistance, 
                                     taskDistance − min(∀trackp.pointi : shortestDistanceToGoal(trackp.pointi )−(trackp .pointi .altitude−GoalAltitude)*GlideRatio)) 
            ∀p :p ∈ PilotsReachedGoal : bestDistance p = taskDistance
            '''
            if task.stopped_time and glide_ratio and total_distance < task.opt_dist:
                alt_over_goal = max(0, alt - goal_altitude)
                if fix_dist_flown + glide_ratio * alt_over_goal > total_distance:
                    '''calculate total distance with glide bonus'''
                    stopped_distance = fix_dist_flown
                    stopped_altitude = alt
                    total_distance = min(
                        fix_dist_flown + glide_ratio * alt_over_goal,
                        task.opt_dist)
        '''Leading coefficient
        LC = taskTime(i)*(bestDistToESS(i-1)^2 - bestDistToESS(i)^2 )
        i : i ? TrackPoints In SS'''
        if lead_coeff and tp.start_done and not tp.ess_done:
            lead_coeff.update(result, my_fix, next_fix)
        '''Airspace Check'''
        if task.airspace_check and airspace:
            # map_fix = [next_fix.rawtime, next_fix.lat, next_fix.lon, alt]
            plot, penalty = airspace.check_fix(next_fix, alt)
            if plot:
                # map_fix.extend(plot)
                '''Airspace Infringement: check if we already have a worse one'''
                airspace_name = plot[2]
                infringement_type = plot[3]
                dist = plot[4]
                separation = plot[5]
                result.infringements.append([
                    next_fix, alt, airspace_name, infringement_type, dist,
                    penalty, separation
                ])
                # print([next_fix, alt, airspace_name, infringement_type, dist, penalty])

    result.last_altitude = 0 if 'alt' not in locals() else alt
    result.last_time = 0 if 'next_fix' not in locals() else next_fix.rawtime
    if livetracking:
        result.height = (0 if not result.first_time or result.landing_time
                         or 'next_fix' not in locals() else next_fix.height)