public static int BeamHeading(Locator start, Locator end) { ////double R = 6371; // km //double dLat = DegreesToRadians(end.Latitude - start.Latitude); //double dLon = DegreesToRadians(end.Longitude - start.Longitude); ////double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + //// Math.Cos(DegreesToRadians(end.Latitude)) * Math.Cos(DegreesToRadians(end.Latitude)) * //// Math.Sin(dLon / 2) * Math.Sin(dLon / 2); ////double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); ////double d = R * c; //double y = Math.Sin(dLon) * Math.Cos(end.Latitude); //double x = Math.Cos(start.Latitude) * Math.Sin(end.Latitude) - // Math.Sin(start.Latitude) * Math.Cos(end.Latitude) * Math.Cos(dLon); //double brng = Math.Atan2(y, x); //return ((int)RadiansToDegrees(brng) + 360) % 360; double lat1 = DegreesToRadians(start.Latitude); double lat2 = DegreesToRadians(end.Latitude); double dLon = DegreesToRadians(end.Longitude - start.Longitude); double y = Math.Sin(dLon) * Math.Cos(lat2); double x = Math.Cos(lat1) * Math.Sin(lat2) - Math.Sin(lat1) * Math.Cos(lat2) * Math.Cos(dLon); int degrees = (int)RadiansToDegrees(Math.Atan2(y, x)); if (degrees < 0) return 360 + degrees; else return degrees; }
public static bool ValidateLocatorTextbox(TextBox tb) { if (tb.TextLength != 6) return true; try { Locator l = new Locator(tb.Text); } catch { return true; } return false; }
private void m_TxtLocator_TextChanged(object sender, EventArgs e) { Locator l = new Locator(m_TxtLocator.Text); if (!l.Equals(Locator.Unknown)) SourceLocator = l; }
private void PopulatePreviousContactsGridCallback(List<Contact> contacts) { Locator ourLocation = m_OurLocatorValue; //m_QSOGrid.Rows.Clear(); string station = m_Station.Text; string band = m_Band.Text; string op = m_OurOperator.Text; for (int i = 1; i < m_ContactTable.RowCount - 1; i++) { int contactsIndex = m_ContactTable.RowCount - i-2; if (contacts.Count > contactsIndex) { Contact c = contacts[contactsIndex]; bool alert = (c.Notes.Contains(station) || c.Notes.Contains(band) || c.Notes.Contains(op)); Label[] rowLabels = m_ContactTableLabels[i - 1]; rowLabels[(int)ContactTableColumns.Band].Text = BandTextFromContact(c); Locator theirLocator; if (c.LocatorReceived != null && !(c.LocatorReceived.Latitude == 0 && c.LocatorReceived.Longitude == 0)) { theirLocator = c.LocatorReceived; } else { PrefixRecord pr = m_CallsignLookup.LookupPrefix(c.Callsign); if (pr != null) theirLocator = new Locator(pr.Latitude, pr.Longitude); else theirLocator = new Locator(0, 0); } rowLabels[(int)ContactTableColumns.Beam].Text = Geographics.BeamHeading(ourLocation, theirLocator).ToString().PadLeft(3, '0'); rowLabels[(int)ContactTableColumns.Distance].Text = ((int)Math.Ceiling(Geographics.GeodesicDistance(ourLocation, theirLocator) / 1000)).ToString(); rowLabels[(int)ContactTableColumns.Callsign].Text = c.Callsign; rowLabels[(int)ContactTableColumns.Comments].Text = c.Notes; if (alert) rowLabels[(int)ContactTableColumns.Comments].BackColor = Color.Pink; else rowLabels[(int)ContactTableColumns.Comments].BackColor = SystemColors.Control; rowLabels[(int)ContactTableColumns.LocatorReceived].Text = c.LocatorReceivedString; rowLabels[(int)ContactTableColumns.RstReceived].Text = c.ReportReceived; rowLabels[(int)ContactTableColumns.RstSent].Text = c.ReportSent; rowLabels[(int)ContactTableColumns.SerialReceived].Text = c.SerialReceived.ToString().PadLeft(3, '0'); rowLabels[(int)ContactTableColumns.SerialSent].Text = c.SerialSent.ToString().PadLeft(3, '0'); rowLabels[(int)ContactTableColumns.Time].Text = c.StartTime.ToString("HHmm"); m_ContactIds[i - 1] = new KeyValuePair<int, int>(c.SourceId, c.Id); if (alert) { Array.ForEach(rowLabels, l => { l.ForeColor = Color.Black; l.BackColor = Color.Pink; }); } else if (string.Equals(c.Station, m_Station.Text, StringComparison.InvariantCultureIgnoreCase)) { Array.ForEach(rowLabels, l => { l.ForeColor = Color.Black; l.BackColor = SystemColors.Control; }); } else { Array.ForEach(rowLabels, l => { l.ForeColor = Color.DarkGray; l.BackColor = SystemColors.Control; }); } //DataGridViewRow row = new DataGridViewRow(); //m_QSOGrid.Rows.Add(row); //row.Cells[(int)ContactTableColumns.Beam].Value = Geographics.BeamHeading(ourLocation, theirLocator).ToString().PadLeft(3, '0'); //row.Cells[(int)ContactTableColumns.Distance].Value = ((int)Math.Ceiling(Geographics.GeodesicDistance(ourLocation, theirLocator) / 1000)).ToString(); //row.Cells[(int)ContactTableColumns.Callsign].Value = c.Callsign; //row.Cells[(int)ContactTableColumns.Comments].Value = c.Notes; //row.Cells[(int)ContactTableColumns.LocatorReceived].Value = c.LocatorReceivedString; //row.Cells[(int)ContactTableColumns.RstReceived].Value = c.ReportReceived; //row.Cells[(int)ContactTableColumns.RstSent].Value = c.ReportSent; //row.Cells[(int)ContactTableColumns.SerialReceived].Value = c.SerialReceived.ToString().PadLeft(3, '0'); //row.Cells[(int)ContactTableColumns.SerialSent].Value = c.SerialSent.ToString().PadLeft(3, '0'); //row.Cells[(int)ContactTableColumns.Time].Value = c.StartTime.ToString("HHmm"); } else { foreach (Label l in m_ContactTableLabels[i - 1]) l.Text = string.Empty; } } }
private void m_OurLocator_TextChanged(object sender, EventArgs e) { if (m_OurLocator.TextLength == 6) { try { m_OurLocatorValue = new Locator(m_OurLocator.Text); Settings.Set("Locator", m_OurLocator.Text); } catch (ArgumentException) { } } }
private void m_Locator_TextChanged(object sender, EventArgs e) { if (m_Locator.TextLength == 6) { try { Locator theirLocator = new Locator(m_Locator.Text); m_Beam.Text = Geographics.BeamHeading(m_OurLocatorValue, theirLocator).ToString(); int distance = (int)Math.Ceiling(Geographics.GeodesicDistance(m_OurLocatorValue, theirLocator) / 1000); if (distance == 0) distance = 1; // By definition - QSOs in same square = 1 point m_Distance.Text = distance.ToString(); } catch (ArgumentException) { m_Beam.Text = m_Distance.Text = string.Empty; } } else { m_Beam.Text = m_Distance.Text = string.Empty; } if (m_Locator.TextLength >= 4) { bool isNewSquare = m_ContactStore.IsNewSquare(m_Locator.Text, BandHelper.Parse(m_Band.Text)); if (isNewSquare) m_Locator.BackColor = Color.LightGreen; else m_Locator.BackColor = SystemColors.Window; } else { m_Locator.BackColor = SystemColors.Window; } }
private void CallsignChangedWorker(string callsign, string ourBandText, Locator ourLocatorValue) { try { string notesText = null; Color notesBackColor = Color.Transparent; string locatorText = null; string beamText = null, distanceText = null, commentsText = null; object[] matchesKnownCalls = null, matchesThisContest = null, locatorMatchesThisContest = null; Locator existingLocator; if (callsign.Length > 2) { List<Band> bands = m_ContactStore.GetPreviousBands(callsign, out existingLocator); Band ourBand = BandHelper.Parse(ourBandText); if (bands.Contains(ourBand)) { notesBackColor = c_DupeColor; List<Contact> previousQsos = m_ContactStore.GetPreviousContacts(callsign); if (previousQsos.Count > 0) { Contact previousQso = previousQsos[previousQsos.Count - 1]; notesText = string.Format("Already worked {0} on {1} (TX: {2} {3:000} / RX: {4} {5:000} on {6} / {7})", callsign, BandHelper.ToString(ourBand), previousQso.ReportSent, previousQso.SerialSent, previousQso.ReportReceived, previousQso.SerialReceived, previousQso.StartTime.ToString("d MMM HH:mm"), previousQso.LocatorReceivedString); } else { notesText = string.Format("Already worked {0} on {1} (Missing QSO details?)", callsign, BandHelper.ToString(ourBand)); } } else if (bands.Count > 0) { notesBackColor = c_WorkedOtherBandsColor; string bandString = string.Empty; foreach (Band b in bands) { bandString += BandHelper.ToString(b) + ", "; } notesText = string.Format("Worked {0} on {1} - {2}", callsign, bandString, existingLocator); if (existingLocator != null) locatorText = existingLocator.ToString(); } else { notesText = string.Empty; notesBackColor = Color.Transparent; } // Do a first guess beam heading etc PrefixRecord pfx = m_CallsignLookup.LookupPrefix(callsign); if (pfx != null) { Locator theirLocator = new Locator(pfx.Latitude, pfx.Longitude); // Only use the DXCC if it's a substantial distance (500km) away from us if (Geographics.GeodesicDistance(ourLocatorValue, theirLocator) > 500 * 1000) { beamText = Geographics.BeamHeading(ourLocatorValue, theirLocator).ToString(); distanceText = Math.Ceiling(Geographics.GeodesicDistance(ourLocatorValue, theirLocator) / 1000).ToString(); } // Only change comments field if it has not been manually changed if ((m_Comments.Text == m_lastComment) || (m_Comments.Text == "")) { m_lastComment = commentsText = pfx.Entity; } } } // Populate the lists of partial callsign matches if (callsign.Length > 0) { matchesKnownCalls = m_ContactStore.GetPartialMatchesKnownCalls(callsign).ToArray(); matchesThisContest = m_ContactStore.GetPartialMatchesThisContest(callsign).ToArray(); } // Also search locators if we've got enough digits for it to be sensibly // distinguished from a callsign if (callsign.Length > 2) { locatorMatchesThisContest = m_ContactStore.GetLocatorMatchesThisContest(callsign).ToArray(); } // Actually populate everything back on the UI thread! if (Disposing || IsDisposed || !IsHandleCreated) return; Invoke(new MethodInvoker(() => { // If the callsign has been changed while we've been doing this work, don't do the update - another request // will have been kicked off since, and we don't want to trample on the later update if (m_Callsign.Text != callsign) return; if (!string.IsNullOrWhiteSpace(notesText)) { m_Notes.Text = notesText; m_Notes.BackColor = notesBackColor; } if (locatorText != null) m_Locator.Text = locatorText; m_Beam.Text = beamText ?? string.Empty; m_Distance.Text = distanceText ?? string.Empty; if (commentsText != null) { m_Comments.Text = commentsText; } if (matchesKnownCalls != null || locatorMatchesThisContest != null) { m_MatchesKnownCalls.BeginUpdate(); m_MatchesKnownCalls.Items.Clear(); if (matchesKnownCalls != null) m_MatchesKnownCalls.Items.AddRange(matchesKnownCalls); if (locatorMatchesThisContest != null) m_MatchesKnownCalls.Items.AddRange(locatorMatchesThisContest); m_MatchesKnownCalls.EndUpdate(); } if (matchesThisContest != null) { m_MatchesThisContest.BeginUpdate(); m_MatchesThisContest.Items.Clear(); m_MatchesThisContest.Items.AddRange(matchesThisContest); m_MatchesThisContest.EndUpdate(); } })); } catch (Exception ex) { } }
//private string GetContactLog(Contact c) //{ // string thisEntry = string.Format("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13} {14} {15} {16} {17} {18}", // c.Time.ToString("yyMMdd"), // c.Time.ToString ("HHmm"), // BandHelper.ToMHzString (c.Band).PadRight(4), // ModeHelper.ToOfficialString(c.Mode).PadRight(3), // c.Callsign.PadRight (15), // c.ReportSent.PadRight (3), // c.SerialSent.ToString().PadRight (4), // c.ReportReceived.PadRight (3), // c.SerialReceived.ToString().PadRight (4), // string.Empty.PadRight (4) /* bonus multiplier etc */, // c.Points.ToString().PadRight (4), // c.Operator.PadRight(6), // c.LocatorReceived.ToString(), // string.Empty.PadRight (1) /* locator multiplier */, // string.Empty.PadRight (3) /* postcode */, // string.Empty.PadRight(1) /* postcode mult */, // string.Empty.PadRight (3) /* country code */, // string.Empty.PadRight (1) /* country code mult */, // c.Notes + "<CE>" // ); // return thisEntry; //} private string GetContactLog(Contact c, Locator sourceLocator, List<string> locator4SquaresSeen, List<string> ukLocator4SquaresSeen, out int points) { // Figure out if this QSO is valid as a mult bool qualifiesForMult; bool qualifiesForUkMult; PrefixRecord prefix = m_CallsignLookup.LookupPrefix(c.Callsign.Trim()); if (prefix == null || prefix.Entity == null) { qualifiesForMult = false; qualifiesForUkMult = false; } else { switch (prefix.Entity) { case "ENGLAND": case "NORTHERN IRELAND": case "WALES": case "SCOTLAND": case "ISLE OF MAN": case "JERSEY": case "GUERNSEY": qualifiesForMult = true; qualifiesForUkMult = true; break; default: qualifiesForMult = true; qualifiesForUkMult = false; break; } } string square4; if (c.LocatorReceivedString != null && c.LocatorReceivedString.Length >= 4) square4 = c.LocatorReceivedString.Substring(0, 4); else square4 = string.Empty; bool newUkSquare = qualifiesForUkMult && !ukLocator4SquaresSeen.Contains(square4.ToLowerInvariant()); if (newUkSquare) ukLocator4SquaresSeen.Add(square4.ToLowerInvariant()); bool newSquare = qualifiesForMult && !locator4SquaresSeen.Contains(square4.ToLowerInvariant()); if (newSquare) locator4SquaresSeen.Add(square4.ToLowerInvariant()); string thisEntry = string.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9};{10};{11};{12};{13};{14}", c.EndTime.ToString("yyMMdd"), c.EndTime.ToString("HHmm"), c.Callsign, string.Empty /* mode code */, c.ReportSent, c.SerialSent, c.ReportReceived, c.SerialReceived, string.Empty /* received exchange */, c.LocatorReceivedString, points = (int)Math.Ceiling(Geographics.GeodesicDistance(sourceLocator, c.LocatorReceived) / 1000), string.Empty /* new exchange */, newSquare ? "N" : string.Empty /* new locator square */, string.Empty /* new DXCC */, string.Empty /* dupe */); return thisEntry; }
public List<Band> GetPreviousBands(string callsign, out Locator locator) { List<Contact> previousContacts = GetPreviousContacts(callsign); List<Band> previousBands = new List<Band>(); locator = null; foreach (Contact c in previousContacts) { if (c.Band != Band.Unknown && !previousBands.Contains(c.Band)) previousBands.Add(c.Band); locator = c.LocatorReceived; } return previousBands; }
public string ExportLog(Locator sourceLocator, Band band) { MySqlConnection conn = OpenConnection; lock (conn) { List<KeyValuePair<int, int>> contactIDs = new List<KeyValuePair<int, int>>(); using (MySqlCommand cmd = conn.CreateCommand()) { cmd.CommandText = "SELECT sourceId, id FROM log WHERE band=?band ORDER BY startTime"; cmd.Parameters.AddWithValue("?band", BandHelper.ToString(band)); using (MySqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) contactIDs.Add(new KeyValuePair<int, int>(reader.GetInt32(0), reader.GetInt32(1))); } } StringBuilder sb = new StringBuilder(); List<string> locator4SquaresSeen = new List<string> (); List<string> ukLocator4SquaresSeen = new List<string>(); int totalPoints = 0; int oDxPoints = 0; Contact oDxContact = null; foreach (KeyValuePair<int, int> id in contactIDs) { int pts; Contact c = LoadContact(id.Key, id.Value); sb.AppendLine(GetContactLog(c, sourceLocator, locator4SquaresSeen, ukLocator4SquaresSeen, out pts)); totalPoints += pts; if (pts > oDxPoints) { oDxContact = c; oDxPoints = pts; } } // Write the header, now we have the various info Reg1TestHeader header = new Reg1TestHeader { Antenna = "ANTENNA", Band = band, Callsign = "G3PYE/P", Club = "Camb-Hams", ContactAddress1 = "13 Harlestones Road", ContactAddress2 = "Cottenham", ContactCall = "M0VFC", ContactCity = "Cambridge", ContactCounty = string.Empty, ContactEmail = "*****@*****.**", ContactName = "Robert Chipperfield", ContactPhone = "07990 646923", ContactPostCode = "CB24 8TR", ContestName = "UKAC", EndDate = new DateTime(2010, 07, 04), HeightAboveGround = 20, HeightAboveSea = 68, Locator = new Locator("JO02CE"), Multipliers = locator4SquaresSeen.Count + ukLocator4SquaresSeen.Count, OdxCall = oDxContact.Callsign, OdxLocator = oDxContact.LocatorReceived, OdxDistance = oDxPoints, Operators = "M0LCM,M0VFC,M0ZRN,M1BXF", Points = totalPoints, Power = 100, Qsos = contactIDs.Count, Receiver = "RECEIVER", Section = "UKAC Restricted", StartDate = new DateTime(2010, 07, 03), TotalScore = totalPoints * (locator4SquaresSeen.Count + ukLocator4SquaresSeen.Count), Transmitter = "TRANSMITTER" }; sb.Insert(0, header.HeaderText); return sb.ToString(); } }
private void m_Locator_TextChanged(object sender, EventArgs e) { try { Locator theirLocator = new Locator(m_Locator.Text); m_Beam.Text = Geographics.BeamHeading(OurLocator, theirLocator).ToString(); int distance = (int)Math.Ceiling(Geographics.GeodesicDistance(OurLocator, theirLocator) / 1000); if (distance == 0) distance = 1; // By definition - QSOs in same square = 1 point m_Distance.Text = distance.ToString(); } catch (ArgumentException) { m_Beam.Text = m_Distance.Text = string.Empty; } }
public static double GeodesicDistance(Locator start, Locator end) { if (start == null || end == null) return 0; double L = DegreesToRadians(end.Longitude - start.Longitude); //var U1 = Math.atan((1-f) * Math.tan(lat1.toRad())); //var U2 = Math.atan((1-f) * Math.tan(lat2.toRad())); //var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1); //var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2); double U1 = Math.Atan((1 - c_Wgs84_F) * Math.Tan(DegreesToRadians(start.Latitude))); double U2 = Math.Atan((1 - c_Wgs84_F) * Math.Tan(DegreesToRadians(end.Latitude))); double sinU1 = Math.Sin(U1); double cosU1 = Math.Cos(U1); double sinU2 = Math.Sin(U2); double cosU2 = Math.Cos(U2); //var lambda = L, lambdaP, iterLimit = 100; // do { // var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda); // var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + // (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda)); // if (sinSigma==0) return 0; // co-incident points // var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda; // var sigma = Math.atan2(sinSigma, cosSigma); // var sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; // var cosSqAlpha = 1 - sinAlpha*sinAlpha; // var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha; // if (isNaN(cos2SigmaM)) cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6) // var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha)); // lambdaP = lambda; // lambda = L + (1-C) * f * sinAlpha * // (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM))); // } while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0); double lambda = L; double lambdaP; double cosSqAlpha, sinSigma, cos2SigmaM, cosSigma, sigma; int iterLimit = 100; do { double sinLambda = Math.Sin(lambda); double cosLambda = Math.Cos(lambda); sinSigma = Math.Sqrt((cosU2 * sinLambda) * (cosU2 * sinLambda) + (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda)); if (sinSigma == 0) return 0; // co-incident points cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda; sigma = Math.Atan2(sinSigma, cosSigma); double sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; cosSqAlpha = 1 - sinAlpha * sinAlpha; cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; if (double.IsNaN(cos2SigmaM)) cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6) double C = c_Wgs84_F / 16 * cosSqAlpha * (4 + c_Wgs84_F * (4 - 3 * cosSqAlpha)); lambdaP = lambda; lambda = L + (1 - C) * c_Wgs84_F * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))); } while (Math.Abs(lambda - lambdaP) > 1e-12 && --iterLimit > 0); if (iterLimit == 0) return double.NaN; // formula failed to converge double uSq = cosSqAlpha * (c_Wgs84_A * c_Wgs84_A - c_Wgs84_B * c_Wgs84_B) / (c_Wgs84_B * c_Wgs84_B); double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))); double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))); double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM))); double s = c_Wgs84_B * A * (sigma - deltaSigma); s = Math.Round(s, 3); // round to 1mm precision return s; }