protected void UpdateRowsForCatClass(CategoryClass.CatClassID idCatClass) { bool fIsGlider = idCatClass == CategoryClass.CatClassID.Glider; divTMG.Visible = fIsGlider; divTailwheel.Visible = CategoryClass.IsAirplane(idCatClass) && !CategoryClass.IsSeaClass(idCatClass); divMultiHeli.Visible = (idCatClass == CategoryClass.CatClassID.Helicopter); bool hasEngine = CategoryClass.HasEngine(idCatClass); rowEngineType.Visible = hasEngine; pnlHighPerfBlock.Visible = ckConstantProp.Enabled = ckComplex.Enabled = hasEngine; divComplex.Style["display"] = hasEngine || fIsGlider ? "inline-block" : "none"; if (!hasEngine) { ckComplex.Checked = ckConstantProp.Checked = ckCowlFlaps.Checked = ckRetract.Checked = false; rblTurbineType.SelectedIndex = 0; } bool fIsLegacyEligible = (idCatClass == CategoryClass.CatClassID.AMEL || idCatClass == CategoryClass.CatClassID.AMES || idCatClass == CategoryClass.CatClassID.Helicopter); pnlLegacyHighPerf.Style["display"] = fIsLegacyEligible ? "inline" : "none"; if (ckLegacyHighPerf.Checked && !fIsLegacyEligible) { HighPerfType = MakeModel.HighPerfType.NotHighPerf; } }
public override void ExamineFlight(ExaminerFlightRow cfr) { bool fIsAirplane = CategoryClass.IsAirplane(cfr.idCatClassOverride); bool fIsIFRSim = (fIsAirplane && cfr.fIsFTD); if (fIsAirplane || cfr.fIsRealAircraft) { miMinInstrumentTime.AddTrainingEvent(cfr.IMC + cfr.IMCSim, ATPMaxIFRSimulator, fIsIFRSim); } if (fIsAirplane && cfr.idCatClassOverride == requiredCatClassID) { bool fIsFullSim = !cfr.fIsRealAircraft && cfr.fIsCertifiedLanding; if (fIsAirplane && (cfr.fIsRealAircraft || fIsFullSim)) { miMinTimeInClass.AddTrainingEvent(cfr.Total, ATPMinTimeInClassFullSimulator, fIsFullSim); } } // Above are the only things to which we will alow training devices. if (!cfr.fIsRealAircraft) { return; } miTotal.AddEvent(Math.Max(CanCreditSICAndFlightEngineer ? cfr.SIC : 0, cfr.Total)); miMinXCTime.AddEvent(cfr.XC); miMinNightTime.AddEvent(cfr.Night); if (CanCreditSICAndFlightEngineer) { decimal flightEngineerTime = 0.0M; cfr.ForEachEvent((pe) => { if (pe.PropTypeID == (int)CustomPropertyType.KnownProperties.IDPropFlightEngineerTime) { flightEngineerTime += pe.DecValue; } }); if (flightEngineerTime > 0) { miTotal.AddTrainingEvent(flightEngineerTime / 3.0M, ATPMaxFlightEngineer, true); } } // Remainder must be done in a real aircraft and it must be in an airplane. // Not clear if the night takeoffs/landings need to be in a real aircraft / airplane, but I'll require it to be safe. if (fIsAirplane) { miMinPIC.AddEvent(cfr.PIC); miMinPICXC.AddEvent(Math.Min(cfr.PIC, cfr.XC)); miMinPICNight.AddEvent(Math.Min(cfr.PIC, cfr.Night)); cfr.ForEachEvent((pe) => { if (pe.PropertyType.IsNightTakeOff) { miNightTO.AddEvent(pe.IntValue); } }); miNightLanding.AddEvent(cfr.cFullStopNightLandings); } }
protected override bool IsQualifyingFlight(ExaminerFlightRow cfr) { if (cfr == null) { throw new ArgumentNullException(nameof(cfr)); } return(cfr.fIsRealAircraft && (cfr.fMotorGlider || CategoryClass.IsAirplane(cfr.idCatClassOverride))); }
private void CheckAirportIssues(LogbookEntryBase le) { IEnumerable <string> rgCodes = airport.SplitCodes(le.Route); foreach (string szCode in rgCodes) { if (szCode.StartsWith(airport.ForceNavaidPrefix, StringComparison.CurrentCultureIgnoreCase)) { continue; } if (szCode.CompareCurrentCultureIgnoreCase("LOCAL") == 0 || szCode.CompareCurrentCultureIgnoreCase("LCL") == 0) { AddIssue(LintOptions.AirportIssues, Resources.FlightLint.warningAirportLocal); continue; } airport ap = alSubset.GetAirportByCode(szCode); if (ap == null) { AddIssue(LintOptions.AirportIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningAirportNotFound, szCode)); } else { AddConditionalIssue((currentCatClassID == CategoryClass.CatClassID.AMEL || currentCatClassID == CategoryClass.CatClassID.ASEL) && ap.IsSeaport, LintOptions.AirportIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningAirportLandPlaneAtSeaport, szCode)); AddConditionalIssue(CategoryClass.IsAirplane(currentCatClassID) && ap.FacilityTypeCode == "H", LintOptions.AirportIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningAirportAirplaneAtHeliport, szCode)); } } // Sanity check for speed if (le.TotalFlightTime > 0) { double dist = alSubset.DistanceForRoute(); double speed = dist / (double)le.TotalFlightTime; AddConditionalIssue(speed > (currentModel.EngineType == MakeModel.TurbineLevel.Piston ? 500 : 1000), LintOptions.AirportIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningAirportUnlikelyImpliedSpeed, speed)); } // Look for missing night takeoffs or landings if (rgCodes.Any()) { airport apDep = alSubset.GetAirportByCode(rgCodes.ElementAt(0)); airport apArr = alSubset.GetAirportByCode(rgCodes.ElementAt(rgCodes.Count() - 1)); if (apDep != null) { AddConditionalIssue(le.FlightStart.HasValue() && !le.CustomProperties.PropertyExistsWithID(CustomPropertyType.KnownProperties.IDPropNightTakeoff) && new SolarTools.SunriseSunsetTimes(le.FlightStart, apDep.LatLong.Latitude, apDep.LatLong.Longitude).IsFAANight, LintOptions.AirportIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningAirportMissingNightTakeoff, apDep.Code, le.FlightStart.UTCFormattedStringOrEmpty(false))); } if (apArr != null) { AddConditionalIssue(le.FlightEnd.HasValue() && le.NightLandings == 0 && new SolarTools.SunriseSunsetTimes(le.FlightEnd, apArr.LatLong.Latitude, apArr.LatLong.Longitude).IsFAANight, LintOptions.AirportIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningAirportMissingNightLanding, apArr.Code, le.FlightEnd.UTCFormattedStringOrEmpty(false))); } } }
/// <summary> /// Returns the LAPL license that corresponds to the category/class in the row; can be used as a key in computing currency /// </summary> /// <param name="cfr">The flight row</param> /// <returns>A string suitable for use as a dictionary key, else empty</returns> public static string KeyForLAPL(ExaminerFlightRow cfr) { if (cfr == null) { throw new ArgumentNullException(nameof(cfr)); } if (cfr.fIsRealAircraft) { if (cfr.fMotorGlider || CategoryClass.IsAirplane(cfr.idCatClassOverride)) { return(Resources.Currency.LAPLA); } if (cfr.idCatClassOverride == CategoryClass.CatClassID.Helicopter) { return(Resources.Currency.LAPLH); } } return(string.Empty); }
public override void ExamineFlight(ExaminerFlightRow cfr) { if (cfr == null) { throw new ArgumentNullException(nameof(cfr)); } // Only ever applies to airplanes if (!CategoryClass.IsAirplane(cfr.idCatClassOverride)) { return; } cfr.FlightProps.ForEachEvent((pfe) => { if (pfe.PropTypeID == (int)CustomPropertyType.KnownProperties.IDProp125291IPC) { AddRecentFlightEvents(cfr.dtFlight, 1); } }); }
/// <summary> /// Instantiates an LAPL Currency appropriate for the flight row. Can be null if we don't support LAPL currency for this aircraft. /// Useful to call KeyForLAPL first since it is a lightweight way (no object instantiation) to check this. /// </summary> /// <param name="cfr">The flight row</param> /// <returns>Null if there is no appropriate currency object.</returns> public static LAPLBase LAPLACurrencyForCategoryClass(ExaminerFlightRow cfr) { if (cfr == null) { throw new ArgumentNullException(nameof(cfr)); } if (!cfr.fIsRealAircraft) { return(null); } if (cfr.fMotorGlider || CategoryClass.IsAirplane(cfr.idCatClassOverride)) { return(new LAPLACurrency()); } else if (cfr.idCatClassOverride == CategoryClass.CatClassID.Helicopter) { return(new LAPLHCurrency()); } else { return(null); } }
public override void ExamineFlight(ExaminerFlightRow cfr) { if (cfr == null) { throw new ArgumentNullException(nameof(cfr)); } if (!cfr.fIsRealAircraft) { return; } bool fIsAirplane = CategoryClass.IsAirplane(cfr.idCatClassOverride); if (fIsAirplane || cfr.idCatClassOverride == CategoryClass.CatClassID.Helicopter || cfr.idCatClassOverride == CategoryClass.CatClassID.Airship) { decimal PICXC = Math.Min(cfr.PIC, cfr.XC); miMinXCPICTime.AddEvent(PICXC); if (fIsAirplane) { miMinXCPICTimeInCategory.AddEvent(PICXC); } } }
protected override bool IsMatchingCategory(CategoryClass.CatClassID ccid) { return(CategoryClass.IsAirplane(ccid)); }
/// <summary> /// Determines if the category/class matches the rating being sought /// </summary> /// <param name="ccid">The category/class</param> /// <returns>True if it applies to the rating</returns> protected bool CatClassMatchesRatingSought(CategoryClass.CatClassID ccid) { switch (RatingSought) { case RatingType.PPLAirplaneMulti: case RatingType.CommercialAMES: case RatingType.CommercialAMEL: case RatingType.PPLPart141MultiEngine: return(ccid == CategoryClass.CatClassID.AMEL || ccid == CategoryClass.CatClassID.AMES); case RatingType.PPLAirplaneSingle: case RatingType.CommercialASEL: case RatingType.CommercialASES: case RatingType.PPLPart141SingleEngine: return(ccid == CategoryClass.CatClassID.ASEL || ccid == CategoryClass.CatClassID.ASES); case RatingType.PPLHelicopter: case RatingType.InstrumentHelicopter: case RatingType.CommercialHelicopter: case RatingType.PPLPart141Helicopter: case RatingType.SAPPLHelicopter: case RatingType.SAPPLNightHelicopter: case RatingType.CAPPLHelicopter: case RatingType.CANightHelicopter: case RatingType.PPLJARHelicopter: return(ccid == CategoryClass.CatClassID.Helicopter); case RatingType.InstrumentAirplane: case RatingType.SAPPLAirplane: case RatingType.SAPPLNightAirplane: case RatingType.CAPPLAirplaneLand: case RatingType.CAPPLAirplaneSea: case RatingType.CANightAirplane: case RatingType.PPLJARAirplane: return(CategoryClass.IsAirplane(ccid)); case RatingType.InstrumentPoweredLift: return(ccid == CategoryClass.CatClassID.PoweredLift); case RatingType.PPLPart141Gyroplane: case RatingType.PPLGyroplane: return(ccid == CategoryClass.CatClassID.Gyroplane); case RatingType.PPLPoweredLift: return(ccid == CategoryClass.CatClassID.PoweredLift); case RatingType.PPLAirship: return(ccid == CategoryClass.CatClassID.Airship); case RatingType.PPLGlider: case RatingType.PPLPart141Glider: case RatingType.CommercialGlider: return(ccid == CategoryClass.CatClassID.Glider); case RatingType.PPLBalloon: return(CategoryClass.IsBalloon(ccid)); case RatingType.CommercialBalloonGas: return(ccid == CategoryClass.CatClassID.GasBalloon); case RatingType.CommercialBalloonHot: return(ccid == CategoryClass.CatClassID.HotAirBalloon); case RatingType.PPLPoweredParachute: return(ccid == CategoryClass.CatClassID.PoweredParachuteLand || ccid == CategoryClass.CatClassID.PoweredParachuteSea); case RatingType.PPLWeightShift: return(ccid == CategoryClass.CatClassID.WeightShiftControlLand || ccid == CategoryClass.CatClassID.WeightShiftControlSea); default: throw new NotImplementedException(); } }
public override void ExamineFlight(ExaminerFlightRow cfr) { if (cfr == null) { throw new ArgumentNullException(nameof(cfr)); } base.ExamineFlight(cfr); if (!cfr.fIsCertifiedLanding) { return; } // 61.57(e) only applies if turbine and type rated. Everything else must be in certified landing, or turbine airplane, or not type rated, or not in the type for this aircraft bool fIsMatchingType = !String.IsNullOrEmpty(TypeDesignator) && cfr.szType.CompareCurrentCultureIgnoreCase(cfr.szType) == 0 && CategoryClass.IsAirplane(cfr.idCatClassOverride) && cfr.turbineLevel.IsTurbine() && !cfr.fIsCertifiedSinglePilot; NightCurrencyOptions nco = fIsMatchingType ? (cfr.fIsRealAircraft ? NightCurrencyOptions.FAR6157eAirplane : NightCurrencyOptions.FAR6157eSim) : NightCurrencyOptions.FAR6157bOnly; // 61.57(e)(4)(i/ii)(A) - 1500 hrs - comes into play after finalize // 61.57(e)(4)(i/ii)(C) - 15 hours in this type in the last 90 days. Only if in an actual aircraft, since it doesn't seem to allow sim time. // Do this first because we'll exclude others if you were pilot monitoring if (nco == NightCurrencyOptions.FAR6157eAirplane) { m_fc6157TimeInType.AddRecentFlightEvents(cfr.dtFlight, cfr.Total); } if (!cfr.FlightProps.PropertyExistsWithID(CustomPropertyType.KnownProperties.IDPropPilotMonitoring)) { // we need to subtract out monitored landings, or ignore all if you were monitoring for the whole flight int cMonitoredLandings = cfr.FlightProps.TotalCountForPredicate(p => p.PropTypeID == (int)CustomPropertyType.KnownProperties.IDPropMonitoredNightLandings); int cMonitoredTakeoffs = cfr.FlightProps.TotalCountForPredicate(p => p.PropTypeID == (int)CustomPropertyType.KnownProperties.IDPropMonitoredNightTakeoffs); // 61.57(e)(4)(i/ii)(B) - passenger currency in this type m_fc6157Passenger.ExamineFlight(cfr); // 61.57(b), 61.57(e)(4)(i/ii)(D) - Night takeoffs/landings if (cfr.cFullStopNightLandings > 0) { AddNighttimeLandingEvent(cfr.dtFlight, Math.Max(cfr.cFullStopNightLandings - cMonitoredLandings, 0), nco); } // Night-time take-offs are also technically required for night currency int cNightTakeoffs = cfr.FlightProps.TotalCountForPredicate(cfp => cfp.PropertyType.IsNightTakeOff); if (cNightTakeoffs > 0) { AddNighttimeTakeOffEvent(cfr.dtFlight, Math.Max(cNightTakeoffs - cMonitoredTakeoffs, 0), nco); } } }