public void CalcMeasure() { if (measureRange.FromLocation != null && measureRange.ToLocation != null) { double lat1 = measureRange.FromLocation.Latitude; double lon1 = measureRange.FromLocation.Longitude; double lat2 = measureRange.ToLocation.Latitude; double lon2 = measureRange.ToLocation.Longitude; measureResult.DST = CalcDistance(lat1, lon1, lat2, lon2) / 1852; double brg = CalcBearing(lat1, lon1, lat2, lon2); measureResult.BRG = (brg + 360) % 360; if (TWS.IsValid()) { measureResult.TWA = TWD.Average(Inst.BufHalfMin) - brg; } double vmc = 0; PolarPoint p = new PolarPoint(); if (SOG.IsValid()) { vmc = SOG.Average(Inst.BufHalfMin); } if (TWD.IsValid() && SPD.IsValid() && NavPolar.IsLoaded) { double Angle = Math.Abs(measureResult.TWA % 360); if (Angle > 180) { Angle = 360 - Angle; } if (Angle < 50) { p = NavPolar.GetBeatTarget(TWS.Average(Inst.BufHalfMin)); vmc = p.SPD * Math.Cos(p.TWA * Math.PI / 180); } else if (Angle > 140) { p = NavPolar.GetRunTarget(TWS.Average(Inst.BufHalfMin)); vmc = -p.SPD * Math.Cos(p.TWA * Math.PI / 180); } else { vmc = NavPolar.GetTarget(Angle, TWS.Average(Inst.BufHalfMin)); } } if (vmc != 0) { measureResult.TTG = TimeSpan.FromHours(measureResult.DST / vmc); } else { measureResult.TTG = TimeSpan.FromHours(0); } } }
public void CalcNav(DateTime now, bool bypassComm = false) { #region Primitives if (rmc_received || bypassComm) { LAT.Val = lat; LON.Val = lon; SOG.Val = sog; COG.Val = cog; LAT.SetValid(now); LON.SetValid(now); SOG.SetValid(now); COG.SetValid(now); RMC_received_Timer.Start(); } if (vhw_received || bypassComm) { SPD.Val = spd; SPD.SetValid(now); } if (dpt_received || bypassComm) { DPT.Val = dpt; DPT.SetValid(now); } if (mwv_received || bypassComm) { AWA.Val = awa; AWS.Val = aws; AWA.SetValid(now); AWS.SetValid(now); } if (mtw_received || bypassComm) { TEMP.Val = temp; TEMP.SetValid(now); } if (hdg_received || bypassComm) { double mv = Properties.Settings.Default.MagVar; //default if (mvar2 != 0) { mv = mvar2; //From HDG } if (mvar1 != 0) { mv = mvar1; //From RMC } MVAR.Val = mv; MVAR.SetValid(now); if (bypassComm) { mv = 0; // heading from log file is "true heading" no need for correction } HDT.Val = hdg + mv; HDT.SetValid(now); } #endregion #region Position, Leg bearing, distance, XTE and VMG if (LAT.IsValid() && LON.IsValid()) { POS.Val.Latitude = LAT.Val; POS.Val.Longitude = LON.Val; POS.SetValid(now); } else { POS.Invalidate(); } if (ActiveLeg != null) { LWLAT.Val = ActiveLeg.FromLocation.Latitude; LWLAT.SetValid(now); LWLON.Val = ActiveLeg.FromLocation.Longitude; LWLON.SetValid(now); LWPT.Val.str = ActiveLeg.FromMark.Name; LWPT.SetValid(now); } else { LWLAT.Invalidate(); LWLON.Invalidate(); LWPT.Invalidate(); } if (!bypassComm || replayLog) { if (ActiveMark != null && POS.IsValid()) { WLAT.Val = ActiveMark.Location.Latitude; WLAT.SetValid(now); WLON.Val = ActiveMark.Location.Longitude; WLON.SetValid(now); WPT.Val.str = ActiveMark.Name; WPT.SetValid(now); BRG.Val = CalcBearing(LAT.Val, LON.Val, WLAT.Val, WLON.Val); BRG.SetValid(now); DST.Val = CalcDistance(LAT.Val, LON.Val, WLAT.Val, WLON.Val) / 1852; DST.SetValid(now); } else { WLAT.Invalidate(); WLON.Invalidate(); WPT.Invalidate(); BRG.IsValid(); DST.IsValid(); } } if (WPT.IsValid() && LWPT.IsValid()) { LEGBRG.Val = CalcBearing(LWLAT.Val, LWLON.Val, WLAT.Val, WLON.Val); LEGBRG.SetValid(now); } else { if (LEGBRG.IsValid()) { LEGBRG.Invalidate(); } } if (LWPT.IsValid()) { XTE.Val = Math.Asin(Math.Sin(DST.Val * 1.852 / 6371) * Math.Sin((BRG.Val - LEGBRG.Val) * Math.PI / 180)) * 6371 / 1.852; XTE.SetValid(now); } else if (XTE.IsValid()) { XTE.Invalidate(); } if (SOG.IsValid() && BRG.IsValid()) { VMGWPT.Val = SOG.Val * Math.Cos((COG.Val - BRG.Val) * Math.PI / 180); VMGWPT.SetValid(now); } else { if (VMGWPT.IsValid()) { VMGWPT.Invalidate(); } } #endregion #region True Wind if (AWA.IsValid() && SPD.IsValid()) { double Dx = AWS.Val * Math.Cos(AWA.Val * Math.PI / 180) - SPD.Val; double Dy = AWS.Val * Math.Sin(AWA.Val * Math.PI / 180); TWS.Val = Math.Sqrt(Dx * Dx + Dy * Dy); TWS.SetValid(now); TWA.Val = Math.Atan2(Dy, Dx) * 180 / Math.PI; TWA.SetValid(now); VMG.Val = SPD.Val * Math.Cos(TWA.Val * Math.PI / 180); VMG.SetValid(now); } else { if (TWS.IsValid()) { TWS.Invalidate(); } if (TWA.IsValid()) { TWA.Invalidate(); } if (VMG.IsValid()) { VMG.Invalidate(); } } if (TWS.IsValid() && HDT.IsValid()) { TWD.Val = HDT.Val + TWA.Val; TWD.SetValid(now); } else { if (TWD.IsValid()) { TWD.Invalidate(); } } #endregion #region Heel //if (AWA.IsValid() && SPD.IsValid()) //{ // double k = 7, // a = 2, // b = 200, // c = 1.5; // var awa = Math.Abs(AWA.Val); // var aws = AWS.Val; // HEEL.Val = k * awa * Math.Pow(aws, c) / (Math.Pow(awa, a) + b); // if (HEEL.Val > 45) HEEL.Val = 45; // HEEL.SetValid(now); //} //else //{ // if (HEEL.IsValid()) // HEEL.Invalidate(); //} #endregion #region Drift if (SOG.IsValid() && COG.IsValid() && HDT.IsValid()) { double Dx = SOG.Val * Math.Cos(COG.Val * Math.PI / 180) - SPD.Val * Math.Cos(HDT.Val * Math.PI / 180); double Dy = SOG.Val * Math.Sin(COG.Val * Math.PI / 180) - SPD.Val * Math.Sin(HDT.Val * Math.PI / 180); DRIFT.Val = Math.Sqrt(Dx * Dx + Dy * Dy); DRIFT.SetValid(now); SET.Val = Math.Atan2(Dy, Dx) * 180 / Math.PI; SET.SetValid(now); } else { if (DRIFT.IsValid()) { DRIFT.Invalidate(); } if (SET.IsValid()) { SET.Invalidate(); } } #endregion #region Performance if (BRG.IsValid() && TWD.IsValid() && SPD.IsValid() && NavPolar.IsLoaded) { double Angle = Math.Abs((TWD.Val - BRG.Val) % 360); if (Angle > 180) { Angle = 360 - Angle; } PolarPoint pb = NavPolar.GetBeatTarget(TWS.Average(Inst.BufHalfMin)); PolarPoint pr = NavPolar.GetRunTarget(TWS.Average(Inst.BufHalfMin)); if (Math.Abs(Angle) <= pb.TWA) // Beating { TGTSPD.Val = pb.SPD; TGTSPD.SetValid(now); TGTTWA.Val = pb.TWA; TGTTWA.SetValid(now); PERF.Val = VMG.Val / (pb.SPD * Math.Cos(pb.TWA * Math.PI / 180)); PERF.SetValid(now); sailingMode = SailingMode.Beating; } if (Math.Abs(Angle) < pr.TWA && Math.Abs(Angle) > pb.TWA) // Reaching { TGTSPD.Val = NavPolar.GetTarget(Math.Abs(TWA.Average(Inst.BufHalfMin)), TWS.Average(Inst.BufHalfMin)); TGTSPD.SetValid(now); TGTTWA.Val = Math.Abs(TWA.Val); TGTTWA.SetValid(now); PERF.Val = SPD.Val / TGTSPD.Val; if (VMGWPT.Val < 0) { PERF.Val = -PERF.Val; } PERF.SetValid(now); sailingMode = SailingMode.Reaching; } if (Math.Abs(Angle) >= pr.TWA) // Running { TGTSPD.Val = pr.SPD; TGTSPD.SetValid(now); TGTTWA.Val = pr.TWA; TGTTWA.SetValid(now); PERF.Val = VMG.Val / (pr.SPD * Math.Cos(pr.TWA * Math.PI / 180)); PERF.SetValid(now); sailingMode = SailingMode.Running; } } else { if (TGTSPD.IsValid()) { TGTSPD.Invalidate(); } if (TGTTWA.IsValid()) { TGTTWA.Invalidate(); } if (PERF.IsValid()) { PERF.Invalidate(); } sailingMode = SailingMode.None; } #endregion #region Line if (p1_set && p2_set && LAT.IsValid() && HDT.IsValid()) { double p3_lat = LAT.Val, p3_lon = LON.Val; if (Properties.Settings.Default.GPSoffsetToBow != 0) { CalcPosition(LAT.Val, LON.Val, Properties.Settings.Default.GPSoffsetToBow, HDT.Val, ref p3_lat, ref p3_lon); } double brg32 = CalcBearing(p3_lat, p3_lon, p2_lat, p2_lon); double dst32 = CalcDistance(p3_lat, p3_lon, p2_lat, p2_lon); LINEDST.Val = dst32 * Math.Sin((linebrg - brg32) * Math.PI / 180); LINEDST.SetValid(now); } else { if (LINEDST.IsValid()) { LINEDST.Invalidate(); } } #endregion #region Route nav if (!bypassComm) { if (ActiveMark != null && DST.IsValid() && !ManOverBoard) { if (DST.Val <= Properties.Settings.Default.WptProximity) { (new SoundPlayer(@".\Sounds\BELL7.WAV")).PlaySync(); if (ActiveLeg != null) { if (ActiveLeg.NextLeg != null) { ActiveLeg = ActiveLeg.NextLeg; ActiveMark = ActiveLeg.ToMark; } else { ActiveMark = null; ActiveLeg = null; ActiveRoute = null; } } else { ActiveMark = null; } } } } if (ActiveRoute != null) { if (ActiveLeg.NextLeg != null && TWD.IsValid()) { NTWA.Val = TWD.Average(Inst.BufTwoMin) - ActiveLeg.NextLeg.Bearing; NTWA.SetValid(); } else { NTWA.Invalidate(); } } #endregion #region Laylines //if (DRIFT.IsValid() && PERF.IsValid() && TWD.IsValid()) //{ // double relset = SET.Average(Inst.BufTenMin) - TWD.Average(Inst.BufHalfMin); // double dxs = TGTSPD.Average(Inst.BufHalfMin) * Math.Cos(TGTTWA.Average(Inst.BufHalfMin) * Math.PI / 180) + DRIFT.Average(Inst.BufTenMin) * Math.Cos(relset * Math.PI / 180); // double dys = TGTSPD.Average(Inst.BufHalfMin) * Math.Sin(TGTTWA.Average(Inst.BufHalfMin) * Math.PI / 180) + DRIFT.Average(Inst.BufTenMin) * Math.Sin(relset * Math.PI / 180); // TGTCOGs.Val = Math.Atan2(dys, dxs) * 180 / Math.PI + TWD.Average(Inst.BufHalfMin); // TGTCOGs.SetValid(now); // TGTSOGs.Val = Math.Sqrt(dxs * dxs + dys * dys); // TGTSOGs.SetValid(now); // double dxp = TGTSPD.Average(Inst.BufHalfMin) * Math.Cos(-TGTTWA.Average(Inst.BufHalfMin) * Math.PI / 180) + DRIFT.Average(Inst.BufTenMin) * Math.Cos(relset * Math.PI / 180); // double dyp = TGTSPD.Average(Inst.BufHalfMin) * Math.Sin(-TGTTWA.Average(Inst.BufHalfMin) * Math.PI / 180) + DRIFT.Average(Inst.BufTenMin) * Math.Sin(relset * Math.PI / 180); // TGTCOGp.Val = Math.Atan2(dyp, dxp) * 180 / Math.PI + TWD.Average(Inst.BufHalfMin); // TGTCOGp.SetValid(now); // TGTSOGp.Val = Math.Sqrt(dxp * dxp + dyp * dyp); // TGTSOGp.SetValid(now); //} //else //{ // if (TGTCOGs.IsValid()) // TGTCOGs.Invalidate(); // if (TGTSOGs.IsValid()) // TGTSOGs.Invalidate(); // if (TGTCOGp.IsValid()) // TGTCOGp.Invalidate(); // if (TGTSOGp.IsValid()) // TGTSOGp.Invalidate(); //} #endregion }