示例#1
0
        public void Load(Packet[] packets, byte driver_index)
        {
            PercentLoadComplete = 0;
            LoadComplete        = false;

            //Load the session summary data first
            LoadSummary(packets, driver_index);

            //Summon this track
            Track ToLoad = Track.Melbourne;

            foreach (Packet p in packets)
            {
                if (p.PacketType == PacketType.Session)
                {
                    SessionPacket sp = (SessionPacket)p;
                    ToLoad    = sp.SessionTrack;
                    SessionId = sp.UniqueSessionId;
                    break;
                }
            }
            TrackDataContainer tdc = TrackDataContainer.LoadTrack(ToLoad);

            //Get list of all laps
            List <byte> AllLaps = new List <byte>();

            foreach (Packet p in packets)
            {
                if (p.PacketType == PacketType.Lap)
                {
                    LapPacket lp           = (LapPacket)p;
                    byte      this_lap_num = lp.FieldLapData[driver_index].CurrentLapNumber;
                    if (AllLaps.Contains(this_lap_num) == false)
                    {
                        AllLaps.Add(this_lap_num);
                    }
                }
            }

            //Set the total number of corners that need to be analyzed (this is used only for progress reporting purposes)
            int number_of_corners = tdc.Corners.Length * AllLaps.Count;

            //Set the % complete to 5% at this point
            PercentLoadComplete = 0.05f;


            //Generate the frames
            PacketFrame[] frames = PacketFrame.CreateAll(packets);
            PercentLoadComplete = 0.15f; //Set it to 15% complete at this point

            //Create the lap analysis objects and fill it with corner analysis data.
            //This process also fills in the LapNumber property
            //This process below should take up the % complete from 15% to 90%
            List <Lap> _Lap = new List <Lap>();

            foreach (byte lap_num in AllLaps)
            {
                Lap this_lap_analysis = new Lap();

                //Fill in the lap number
                this_lap_analysis.LapNumber = lap_num;

                //Get all of the frames for this lap
                List <PacketFrame> ThisLapFrames = new List <PacketFrame>();
                foreach (PacketFrame pf in frames)
                {
                    if (pf.Lap.FieldLapData[driver_index].CurrentLapNumber == lap_num)
                    {
                        ThisLapFrames.Add(pf);
                    }
                }



                //Find the best packetframe for each corner
                List <TelemetrySnapshot> _TelemetrySnapshot = new List <TelemetrySnapshot>();
                int c = 1;
                for (c = 1; c <= tdc.Corners.Length; c++)
                {
                    //Find the best packetframe for this corner
                    TrackLocation this_corner        = tdc.Corners[c - 1];
                    PacketFrame   winner             = ThisLapFrames[0];
                    float         min_distance_found = float.MaxValue;
                    foreach (PacketFrame pf in ThisLapFrames)
                    {
                        TrackLocation this_location = new TrackLocation();
                        this_location.PositionX = pf.Motion.FieldMotionData[driver_index].PositionX;
                        this_location.PositionY = pf.Motion.FieldMotionData[driver_index].PositionY;
                        this_location.PositionZ = pf.Motion.FieldMotionData[driver_index].PositionZ;
                        this_location.Sector    = pf.Lap.FieldLapData[driver_index].Sector;

                        if (this_location.Sector == this_corner.Sector) //Only consider packets that are in the same sector
                        {
                            float this_distance = ApexVisualToolkit.DistanceBetweenTwoPoints(this_corner, this_location);
                            if (this_distance < min_distance_found && this_distance < 40) //It has to be be within 40. If it isn't, it is not considered a corner hit!
                            {
                                winner             = pf;
                                min_distance_found = this_distance;
                            }
                        }
                    }

                    //Add the corner analysis
                    TelemetrySnapshot ca = new TelemetrySnapshot();
                    ca.LocationNumber = (byte)c;
                    if (min_distance_found < float.MaxValue) //we found a suitable packet, so therefore the min distance shold be less than max. Fill in the details
                    {
                        //Position
                        ca.PositionX = winner.Motion.FieldMotionData[driver_index].PositionX;
                        ca.PositionY = winner.Motion.FieldMotionData[driver_index].PositionY;
                        ca.PositionZ = winner.Motion.FieldMotionData[driver_index].PositionZ;

                        //Velocity
                        ca.VelocityX = winner.Motion.FieldMotionData[driver_index].VelocityX;
                        ca.VelocityY = winner.Motion.FieldMotionData[driver_index].VelocityY;
                        ca.VelocityZ = winner.Motion.FieldMotionData[driver_index].VelocityZ;

                        //gForce
                        ca.gForceLateral      = winner.Motion.FieldMotionData[driver_index].gForceLateral;
                        ca.gForceLongitudinal = winner.Motion.FieldMotionData[driver_index].gForceLongitudinal;
                        ca.gForceVertical     = winner.Motion.FieldMotionData[driver_index].gForceVertical;

                        //Yaw, pitch, roll
                        ca.Yaw   = winner.Motion.FieldMotionData[driver_index].Yaw;
                        ca.Pitch = winner.Motion.FieldMotionData[driver_index].Pitch;
                        ca.Roll  = winner.Motion.FieldMotionData[driver_index].Roll;

                        //Lap data
                        ca.CurrentLapTime = winner.Lap.FieldLapData[driver_index].CurrentLapTime;
                        ca.CarPosition    = winner.Lap.FieldLapData[driver_index].CarPosition;
                        ca.LapInvalid     = winner.Lap.FieldLapData[driver_index].CurrentLapInvalid;
                        ca.Penalties      = winner.Lap.FieldLapData[driver_index].Penalties;

                        //Telemetry data
                        ca.SpeedKph  = winner.Telemetry.FieldTelemetryData[driver_index].SpeedKph;
                        ca.Throttle  = winner.Telemetry.FieldTelemetryData[driver_index].Throttle;
                        ca.Steer     = winner.Telemetry.FieldTelemetryData[driver_index].Steer;
                        ca.Brake     = winner.Telemetry.FieldTelemetryData[driver_index].Brake;
                        ca.Clutch    = winner.Telemetry.FieldTelemetryData[driver_index].Clutch;
                        ca.Gear      = winner.Telemetry.FieldTelemetryData[driver_index].Gear;
                        ca.EngineRpm = winner.Telemetry.FieldTelemetryData[driver_index].EngineRpm;
                        ca.DrsActive = winner.Telemetry.FieldTelemetryData[driver_index].DrsActive;

                        //Wheel data arrays
                        ca.BrakeTemperature       = winner.Telemetry.FieldTelemetryData[driver_index].BrakeTemperature;
                        ca.TyreSurfaceTemperature = winner.Telemetry.FieldTelemetryData[driver_index].TyreSurfaceTemperature;
                        ca.TyreInnerTemperature   = winner.Telemetry.FieldTelemetryData[driver_index].TyreInnerTemperature;

                        //Other data
                        ca.EngineTemperature = winner.Telemetry.FieldTelemetryData[driver_index].EngineTemperature;

                        //Car status
                        ca.SelectedFuelMix = winner.CarStatus.FieldCarStatusData[driver_index].SelectedFuelMix;
                        ca.FuelLevel       = winner.CarStatus.FieldCarStatusData[driver_index].FuelLevel;

                        //Other wheel data arrays
                        ca.TyreWearPercent   = winner.CarStatus.FieldCarStatusData[driver_index].TyreWearPercentage;
                        ca.TyreDamagePercent = winner.CarStatus.FieldCarStatusData[driver_index].TyreDamagePercentage;

                        //Other data
                        ca.FrontLeftWingDamage  = winner.CarStatus.FieldCarStatusData[driver_index].FrontLeftWingDamagePercent;
                        ca.FrontRightWingDamage = winner.CarStatus.FieldCarStatusData[driver_index].FrontRightWingDamagePercent;
                        ca.RearWingDamage       = winner.CarStatus.FieldCarStatusData[driver_index].RearWingDamagePercent;
                        ca.ErsStored            = winner.CarStatus.FieldCarStatusData[driver_index].ErsStoredEnergyJoules;

                        //Add it to the list. (This is in this block because nothing should be added to the list if the corner was not found. So NO EMPTY TelemetrySnapshots in this array to represent a corner that was not found)
                        _TelemetrySnapshot.Add(ca);
                    }
                    else //if we were not able to find a suitable packet for that corner, populate it with just a blank PacketFrame as a place holder.
                    {
                        //Do nothing (that Lap just won't have data for that corner. It can scan through all of the track locations )
                    }
                }
                this_lap_analysis.Corners = _TelemetrySnapshot.ToArray();


                //Get the tyre compound that is being used for this lap
                List <TyreCompound> CompoundsUsedThisLap = new List <TyreCompound>();
                foreach (PacketFrame pf in ThisLapFrames)
                {
                    //Add the compound to the list
                    TyreCompound this_comp = pf.CarStatus.FieldCarStatusData[driver_index].EquippedTyreCompound;
                    if (CompoundsUsedThisLap.Contains(this_comp) == false)
                    {
                        CompoundsUsedThisLap.Add(this_comp);
                    }
                }
                if (CompoundsUsedThisLap.Count == 1) //If there is only one tyre compound that was used this lap, plug that one in
                {
                    this_lap_analysis.EquippedTyreCompound = CompoundsUsedThisLap[0];
                }
                else //If there were multiple compounds that were used, check which one was used more
                {
                    //Find the one that is used most
                    int          HighestSeen = 0;
                    TyreCompound winner      = CompoundsUsedThisLap[0];
                    foreach (TyreCompound tc in CompoundsUsedThisLap)
                    {
                        //Count it
                        int this_times = 0;
                        foreach (PacketFrame pf in ThisLapFrames)
                        {
                            TyreCompound thistc = pf.CarStatus.FieldCarStatusData[driver_index].EquippedTyreCompound;
                            if (thistc == tc)
                            {
                                this_times = this_times + 1;
                            }
                        }

                        //Is it greater? if so, kick out the winner
                        if (this_times >= HighestSeen)
                        {
                            HighestSeen = this_times;
                            winner      = tc;
                        }
                    }

                    //Plug it in
                    this_lap_analysis.EquippedTyreCompound = winner;
                }



                //Add this to the list of lap analyses
                _Lap.Add(this_lap_analysis);

                //Update the percent complete
                float AdditionalPercentCompletePerLap = (0.90f - 0.15f) / (float)AllLaps.Count;
                PercentLoadComplete = PercentLoadComplete + AdditionalPercentCompletePerLap;
            }


            //Sort the packets by time - this is not required for the above process, so I am doing it here for the timing stuff
            List <PacketFrame> frames_aslist = frames.ToList();
            List <PacketFrame> frames_sorted = new List <PacketFrame>();

            while (frames_aslist.Count > 0)
            {
                PacketFrame winner = frames_aslist[0];
                foreach (PacketFrame pf in frames_aslist)
                {
                    if (pf.Telemetry.SessionTime < winner.Telemetry.SessionTime)
                    {
                        winner = pf;
                    }
                }
                frames_sorted.Add(winner);
                frames_aslist.Remove(winner);
            }


            //Plug in the sector times and lap times
            PacketFrame last_frame = null;

            foreach (PacketFrame this_frame in frames_sorted)
            {
                if (last_frame != null)
                {
                    float S1_Time_S = 0;
                    float S2_Time_S = 0;
                    float S3_Time_S = 0;
                    float LapTime_S = 0;
                    bool  Lap_Invalid_In_Last_Frame = false;

                    if (last_frame.Lap.FieldLapData[driver_index].Sector == 1 && this_frame.Lap.FieldLapData[driver_index].Sector == 2) //We went from sector 1 to sector 2
                    {
                        S1_Time_S = (float)this_frame.Lap.FieldLapData[driver_index].Sector1TimeMilliseconds / 1000f;
                    }
                    else if (last_frame.Lap.FieldLapData[driver_index].Sector == 2 && this_frame.Lap.FieldLapData[driver_index].Sector == 3) //We went from sector 2 to sector 3
                    {
                        S2_Time_S = (float)this_frame.Lap.FieldLapData[driver_index].Sector2TimeMilliseconds / 1000f;
                    }
                    else if (last_frame.Lap.FieldLapData[driver_index].CurrentLapNumber < this_frame.Lap.FieldLapData[driver_index].CurrentLapNumber) //We just finished the lap, and thus sector 3
                    {
                        float last_s1_seconds = (float)last_frame.Lap.FieldLapData[driver_index].Sector1TimeMilliseconds / 1000f;
                        float last_s2_seconds = (float)last_frame.Lap.FieldLapData[driver_index].Sector2TimeMilliseconds / 1000f;
                        LapTime_S = this_frame.Lap.FieldLapData[driver_index].LastLapTime;
                        S3_Time_S = LapTime_S - last_s1_seconds - last_s2_seconds;
                    }

                    if (last_frame.Lap.FieldLapData[driver_index].CurrentLapInvalid)
                    {
                        Lap_Invalid_In_Last_Frame = true;
                    }


                    //If any of the numbers up there changed (are not 0), it means that we either changed sector or changed lap. If we did, we need to plug that data into the Lap
                    if (S1_Time_S > 0 || S2_Time_S > 0 || S3_Time_S > 0 || Lap_Invalid_In_Last_Frame)
                    {
                        //Find the lap analysis
                        foreach (Lap la in _Lap)
                        {
                            if (la.LapNumber == last_frame.Lap.FieldLapData[driver_index].CurrentLapNumber)
                            {
                                if (S1_Time_S > 0)
                                {
                                    la.Sector1Time = S1_Time_S;
                                }

                                if (S2_Time_S > 0)
                                {
                                    la.Sector2Time = S2_Time_S;
                                }

                                if (S3_Time_S > 0)
                                {
                                    la.Sector3Time = S3_Time_S;
                                }

                                if (Lap_Invalid_In_Last_Frame)
                                {
                                    la.LapInvalid = true;
                                }
                            }
                        }
                    }
                }
                last_frame = this_frame;
            }
            PercentLoadComplete = 0.95f; //Mark the percent complete as 95%

            #region "Get fuel consumption for each lap"

            foreach (byte lapnum in AllLaps)
            {
                //Get all packets for this lap
                List <PacketFrame> lap_frames = new List <PacketFrame>();
                foreach (PacketFrame frame in frames_sorted)
                {
                    if (frame.Lap.FieldLapData[driver_index].CurrentLapNumber == lapnum)
                    {
                        lap_frames.Add(frame);
                    }
                }

                //Get the min and max and then plug it in
                if (lap_frames.Count > 0)
                {
                    float fuel_start = lap_frames[0].CarStatus.FieldCarStatusData[driver_index].FuelLevel;
                    float fuel_end   = lap_frames[lap_frames.Count - 1].CarStatus.FieldCarStatusData[driver_index].FuelLevel;
                    float fuel_used  = fuel_end - fuel_start;
                    fuel_used = fuel_used * -1;

                    foreach (Lap la in _Lap)
                    {
                        if (la.LapNumber == lapnum)
                        {
                            la.FuelConsumed = fuel_used;
                        }
                    }
                }
            }

            #endregion

            #region "Get percent on throttle/brake/coasting/max throttle/max brake"

            foreach (byte lapnum in AllLaps)
            {
                //Get all packets for this lap
                List <PacketFrame> lap_frames = new List <PacketFrame>();
                foreach (PacketFrame frame in frames_sorted)
                {
                    if (frame.Lap.FieldLapData[driver_index].CurrentLapNumber == lapnum)
                    {
                        lap_frames.Add(frame);
                    }
                }

                //Set up counter variables
                int OnThrottle   = 0;
                int OnBrake      = 0;
                int Coasting     = 0;
                int Overlap      = 0;
                int FullThrottle = 0;
                int FullBrake    = 0;

                //Do the calculations
                foreach (PacketFrame frame in lap_frames)
                {
                    TelemetryPacket.CarTelemetryData ctd = frame.Telemetry.FieldTelemetryData[driver_index];


                    //Basics
                    if (ctd.Throttle > 0 && ctd.Brake == 0)
                    {
                        OnThrottle = OnThrottle + 1;
                    }
                    else if (ctd.Brake > 0 && ctd.Throttle == 0)
                    {
                        OnBrake = OnBrake + 1;
                    }
                    else if (ctd.Throttle == 0 && ctd.Brake == 0)
                    {
                        Coasting = Coasting + 1;
                    }
                    else if (ctd.Throttle > 0 && ctd.Brake > 0)
                    {
                        Overlap = Overlap + 1;
                    }

                    //Full pressures
                    if (ctd.Throttle == 1)
                    {
                        FullThrottle = FullThrottle + 1;
                    }
                    if (ctd.Brake == 1)
                    {
                        FullBrake = FullBrake + 1;
                    }
                }

                //Do the calculations
                float percent_on_throttle = (float)OnThrottle / (float)lap_frames.Count;
                float percent_on_brake    = (float)OnBrake / (float)lap_frames.Count;
                float percent_coasting    = (float)Coasting / (float)lap_frames.Count;
                float percent_overlap     = (float)Overlap / (float)lap_frames.Count;
                float full_throttle       = (float)FullThrottle / (float)lap_frames.Count;
                float full_brake          = (float)FullBrake / (float)lap_frames.Count;

                //plug them in
                foreach (Lap la in _Lap)
                {
                    if (la.LapNumber == lapnum)
                    {
                        la.PercentOnThrottle           = percent_on_throttle;
                        la.PercentOnBrake              = percent_on_brake;
                        la.PercentCoasting             = percent_coasting;
                        la.PercentThrottleBrakeOverlap = percent_overlap;
                        la.PercentOnMaxThrottle        = full_throttle;
                        la.PercentOnMaxBrake           = full_brake;
                    }
                }
            }

            #endregion

            #region "Get ERS deployed + harvested"

            foreach (byte lapnum in AllLaps)
            {
                //Get all packets for this lap
                List <PacketFrame> lap_frames = new List <PacketFrame>();
                foreach (PacketFrame frame in frames_sorted)
                {
                    if (frame.Lap.FieldLapData[driver_index].CurrentLapNumber == lapnum)
                    {
                        lap_frames.Add(frame);
                    }
                }

                float ers_dep = lap_frames[lap_frames.Count - 1].CarStatus.FieldCarStatusData[driver_index].ErsDeployedThisLap;
                float ers_har = lap_frames[lap_frames.Count - 1].CarStatus.FieldCarStatusData[driver_index].ErsHarvestedThisLapByMGUH + lap_frames[lap_frames.Count - 1].CarStatus.FieldCarStatusData[driver_index].ErsHarvestedThisLapByMGUK;

                //plug them in
                foreach (Lap la in _Lap)
                {
                    if (la.LapNumber == lapnum)
                    {
                        la.ErsDeployed  = ers_dep;
                        la.ErsHarvested = ers_har;
                    }
                }
            }

            #endregion

            #region "Get gear changes"

            foreach (byte lapnum in AllLaps)
            {
                //Get all packets for this lap
                List <PacketFrame> lap_frames = new List <PacketFrame>();
                foreach (PacketFrame frame in frames_sorted)
                {
                    if (frame.Lap.FieldLapData[driver_index].CurrentLapNumber == lapnum)
                    {
                        lap_frames.Add(frame);
                    }
                }

                //Count the number of gear changes
                int         gear_changes = 0;
                PacketFrame last_frame_  = null;
                foreach (PacketFrame frame in lap_frames)
                {
                    if (last_frame_ != null)
                    {
                        sbyte last_gear = last_frame_.Telemetry.FieldTelemetryData[driver_index].Gear;
                        sbyte this_gear = frame.Telemetry.FieldTelemetryData[driver_index].Gear;
                        if (this_gear != last_gear)
                        {
                            gear_changes = gear_changes + 1;
                        }
                    }
                    last_frame_ = frame;
                }

                //Plug it in
                foreach (Lap la in _Lap)
                {
                    if (la.LapNumber == lapnum)
                    {
                        la.GearChanges = gear_changes;
                    }
                }
            }

            #endregion

            #region  "Get Top Speed"

            foreach (byte lapnum in AllLaps)
            {
                //Get all packets for this lap
                List <PacketFrame> lap_frames = new List <PacketFrame>();
                foreach (PacketFrame frame in frames_sorted)
                {
                    if (frame.Lap.FieldLapData[driver_index].CurrentLapNumber == lapnum)
                    {
                        lap_frames.Add(frame);
                    }
                }

                //Get values
                ushort max_kph = 0;
                ushort max_mph = 0;
                foreach (PacketFrame frame in lap_frames)
                {
                    TelemetryPacket.CarTelemetryData ctd = frame.Telemetry.FieldTelemetryData[driver_index];
                    if (ctd.SpeedKph > max_kph)
                    {
                        max_kph = ctd.SpeedKph;
                    }
                    if (ctd.SpeedMph > max_mph)
                    {
                        max_mph = ctd.SpeedMph;
                    }
                }

                //Plug it in
                foreach (Lap la in _Lap)
                {
                    if (la.LapNumber == lapnum)
                    {
                        la.TopSpeedKph = max_kph;
                    }
                }
            }

            #endregion

            #region "Get average incremental tyre wear"

            foreach (byte lapnum in AllLaps)
            {
                //Get all packets for this lap
                List <PacketFrame> lap_frames = new List <PacketFrame>();
                foreach (PacketFrame frame in frames_sorted)
                {
                    if (frame.Lap.FieldLapData[driver_index].CurrentLapNumber == lapnum)
                    {
                        lap_frames.Add(frame);
                    }
                }

                WheelDataArray tyrewear_start    = lap_frames[0].CarStatus.FieldCarStatusData[driver_index].TyreWearPercentage;
                WheelDataArray tyrewear_end      = lap_frames[lap_frames.Count - 1].CarStatus.FieldCarStatusData[driver_index].TyreWearPercentage;
                float          AvgTyreWear_Start = (tyrewear_start.RearLeft + tyrewear_start.RearRight + tyrewear_start.FrontLeft + tyrewear_start.FrontRight) / 4f;
                float          AvgTyreWear_End   = (tyrewear_end.RearLeft + tyrewear_end.RearRight + tyrewear_end.FrontLeft + tyrewear_end.FrontRight) / 4f;
                float          avginctyrewear    = AvgTyreWear_End - AvgTyreWear_Start;

                //Plug it in
                foreach (Lap la in _Lap)
                {
                    if (la.LapNumber == lapnum)
                    {
                        //Incremental tyre wear
                        la.IncrementalTyreWear            = new WheelDataArray();
                        la.IncrementalTyreWear.RearLeft   = tyrewear_end.RearLeft - tyrewear_start.RearLeft;
                        la.IncrementalTyreWear.RearRight  = tyrewear_end.RearRight - tyrewear_start.RearRight;
                        la.IncrementalTyreWear.FrontLeft  = tyrewear_end.FrontLeft - tyrewear_start.FrontLeft;
                        la.IncrementalTyreWear.FrontRight = tyrewear_end.FrontRight - tyrewear_start.FrontRight;

                        //Beginning (snapshot) tyre wear
                        la.BeginningTyreWear            = new WheelDataArray();
                        la.BeginningTyreWear.RearLeft   = tyrewear_start.RearLeft;
                        la.BeginningTyreWear.RearRight  = tyrewear_start.RearRight;
                        la.BeginningTyreWear.FrontLeft  = tyrewear_start.FrontLeft;
                        la.BeginningTyreWear.FrontRight = tyrewear_start.FrontRight;
                    }
                }
            }

            #endregion

            //Close off the laps
            Laps = _Lap.ToArray();

            #region "Now that we have the lap analyses, generate the corner performance analyses (Lap Analyses MUST BE DONE before this)"

            //Generate all of the corner performances
            List <LocationPerformanceAnalysis> corner_performances = new List <LocationPerformanceAnalysis>();
            for (int c = 0; c < tdc.Corners.Length; c++)
            {
                LocationPerformanceAnalysis cpa = new LocationPerformanceAnalysis();

                //Copy over the data from the TrackLocationOptima (by doing a quick Json serialization/deserialization)
                cpa = JsonConvert.DeserializeObject <LocationPerformanceAnalysis>(JsonConvert.SerializeObject(tdc.Corners[c]));

                //Plug in the corner #
                cpa.LocationNumber = (byte)(c + 1);

                List <ushort> Speeds    = new List <ushort>(); //A list of speeds that were carried through this corner
                List <sbyte>  Gears     = new List <sbyte>();  //A list of gears that the driver used through this corner
                List <float>  Distances = new List <float>();

                //Collect the data for each lap
                foreach (Lap la in Laps)
                {
                    //Go through all of the corners for this lap. If you find a corner that matches the corner number that we are analyzing, add the details to the list.
                    foreach (TelemetrySnapshot ts in la.Corners)
                    {
                        if (ts.LocationNumber == (c + 1))
                        {
                            Speeds.Add(ts.SpeedKph);
                            Gears.Add(ts.Gear);
                        }
                    }

                    // Had to comment out the below on 11/24/2020. The distance to apex method is removed.
                    // //Collect the distance to apex
                    // TelemetrySnapshot ca = la.Corners[c];
                    // if (ca.Motion != null) //The motion packet is required to calculate distance to apex BECAUSE the motion packet contains position data
                    // {
                    //     Distances.Add(ca.DistanceToApex());
                    // }
                }

                //Get the average speed
                float speed_avg = 0;
                if (Speeds.Count > 0)
                {
                    foreach (ushort us in Speeds)
                    {
                        speed_avg = speed_avg + (float)us;
                    }
                    speed_avg           = speed_avg / (float)Speeds.Count;
                    cpa.AverageSpeedKph = speed_avg;
                }
                else
                {
                    cpa.AverageSpeedKph = float.NaN;
                }

                //Get the average gear
                float gear_avg = 0;
                if (Gears.Count > 0)
                {
                    foreach (sbyte sb in Gears)
                    {
                        gear_avg = gear_avg + (float)sb;
                    }
                    gear_avg        = gear_avg / (float)Gears.Count;
                    cpa.AverageGear = gear_avg;
                }
                else
                {
                    cpa.AverageGear = float.NaN;
                }

                //Get average distance to apex
                float distance_avg = 0;
                if (Distances.Count > 0)
                {
                    foreach (float f in Distances)
                    {
                        distance_avg = distance_avg + f;
                    }
                    distance_avg = distance_avg / (float)Distances.Count;
                    cpa.AverageDistanceToApex = distance_avg;
                }
                else
                {
                    cpa.AverageDistanceToApex = float.NaN;
                }

                #region "Consistency rating"

                if (Speeds.Count > 0 && Gears.Count > 0 && Distances.Count > 0) //Only do the consistency rating if we have at least SOME data from all 3 parts
                {
                    //Get a list of floats - speeds
                    List <float> Speeds_float = new List <float>();
                    foreach (ushort us in Speeds)
                    {
                        Speeds_float.Add((float)us);
                    }

                    //Get a list of floats - gears
                    List <float> Gears_float = new List <float>();
                    foreach (sbyte sb in Gears)
                    {
                        Gears_float.Add((float)sb);
                    }

                    //Calculate the standard deviations
                    float stdev_Speeds    = MathToolkit.StandardDeviation(Speeds_float.ToArray());
                    float stdev_Gears     = MathToolkit.StandardDeviation(Gears_float.ToArray());
                    float stdev_Distances = MathToolkit.StandardDeviation(Distances.ToArray());

                    //Turn them into ratings by turning them into percentages of the average (if you don't do this, the higher numbers on corners would result in higher st deviation)
                    float rating_Speeds    = stdev_Speeds / speed_avg;
                    float rating_Gears     = stdev_Gears / gear_avg;
                    float rating_Distances = stdev_Distances / distance_avg;

                    //Calculate the consistency rating
                    List <float> ConsistencyRatingAgg = new List <float>();
                    ConsistencyRatingAgg.Add(rating_Speeds);
                    ConsistencyRatingAgg.Add(rating_Gears * 0.5f); //The float is a weight (higher = this category deserves more weight)
                    ConsistencyRatingAgg.Add(rating_Distances * 0.35f);

                    //Plug in the consistency rating
                    cpa.InconsistencyRating = ConsistencyRatingAgg.Sum();
                }
                else
                {
                    cpa.InconsistencyRating = float.NaN;
                }



                #endregion

                corner_performances.Add(cpa);
            }

            //Plug in all of the corner performances
            Corners = corner_performances.ToArray();

            #endregion



            //Shut down
            PercentLoadComplete = 1; //Mark the percent complete as 100%
            LoadComplete        = true;
        }
示例#2
0
        //Get times between corners
        //This will return an array of float values. These float values indicate the gaps between the corners.
        //First value will be gap between the start of lap (start line) and the first corner
        //Lat value will be gap between the last corner and end of lap (start line)
        //In the senario that a corner is missed (i.e. they did not hit corner 2), the values that would have been 1-2 and 2-3 will be NaN
        public float[] CornerGapTimes(byte lap_num)
        {
            #region "Error Checking"

            if (lap_num < 1)
            {
                throw new Exception("Lap #" + lap_num.ToString() + " is invalid.");
            }

            //make sure we have that lap
            bool HasLap = false;
            foreach (Lap l in Laps)
            {
                if (l.LapNumber == lap_num)
                {
                    HasLap = true;
                }
            }
            if (HasLap == false)
            {
                throw new Exception("This session does not have lap #" + lap_num.ToString() + " so it is impossible to calculate the corner gap times.");
            }

            #endregion

            //Find the lap in question
            Lap SubjectLap = null;
            foreach (Lap l in Laps)
            {
                if (l.LapNumber == lap_num)
                {
                    SubjectLap = l;
                }
            }

            //Get the track so we know how many corners should exist here
            TrackDataContainer tdc = TrackDataContainer.LoadTrack(Circuit);

            List <float> ToReturn = new List <float>();
            for (int c = 0; c < (tdc.Corners.Length + 1); c++)
            {
                //In this C loop:
                // 0 = Start - 1
                // 1 = 1 - 2
                // 2 = 2 - 3
                // 3 = 3 - 4
                // etc...
                //Last corner # = Last corner - Lap end

                //Find this corner
                TelemetrySnapshot Corner1 = null;
                TelemetrySnapshot Corner2 = null;
                foreach (TelemetrySnapshot ts in SubjectLap.Corners)
                {
                    if (ts.LocationNumber == c) //Corner 1 (corrner at start of gap)
                    {
                        Corner1 = ts;
                    }
                    else if (ts.LocationNumber == (c + 1)) //Corner 2 (corner at end of gap)
                    {
                        Corner2 = ts;
                    }
                }

                //If it is the first corner, get the current lap time (time it has been since it crossed the start/finish line)
                if (c == 0)
                {
                    //if we have the corner (they hit the apex), write the time
                    if (Corner2 != null)
                    {
                        ToReturn.Add(Corner2.CurrentLapTime);
                    }
                    else //If we weren't able to find one (one doesn't exist)
                    {
                        ToReturn.Add(float.NaN);
                    }
                }
                else if (c > 0 && c < tdc.Corners.Length) // This is for any other middle corner (not the first corner, not the last corner)
                {
                    //Even though we try and go find it, it is possible that the next corner will not be there
                    //This would be caused by the driver not getting close enough to the apex to trigger it to register as a corner.

                    //If either the current corner or next corner are null, just plug in a NaN value
                    if (Corner1 == null || Corner2 == null)
                    {
                        ToReturn.Add(float.NaN);
                    }
                    else
                    {
                        ToReturn.Add(Corner2.CurrentLapTime - Corner1.CurrentLapTime);
                    }
                }
                else if (c == tdc.Corners.Length) // If this is the last corner in the lap (we need to measure the time until it took to get to the start line from the last corner)
                {
                    //If we have the last corner (they hit the apex)
                    if (Corner1 != null)
                    {
                        //The way we can measure the amount of time from the apex of the last corner to the finish line for this lap: This lap time - the current lap time at the time they were at the apex of the last corner

                        //If all 3 sectors have time (they FINISHED the lap!)
                        if (SubjectLap.Sector1Time > 0 && SubjectLap.Sector2Time > 0 && SubjectLap.Sector3Time > 0)
                        {
                            ToReturn.Add(SubjectLap.LapTime() - Corner1.CurrentLapTime);
                        }
                        else //If the lap was never comleted, return NaN
                        {
                            ToReturn.Add(float.NaN);
                        }
                    }
                    else //If the last corner was not found
                    {
                        ToReturn.Add(float.NaN);
                    }
                }
            }

            return(ToReturn.ToArray());
        }