using System; using System.Collections.Generic; namespace CoordinateSharp { //CURRENT ALTITUDE IS SET CONSTANT AT 100M. POSSIBLY NEED TO ADJUST TO ALLOW USER PASS. //Altitude adjustments appear to have minimal effect on eclipse timing. These were mainly used //to signify eclipses that had already started during rise and set times on the NASA calculator //SOME TIMES AND ALTS WERE RETURNED WITH COLOR AND STYLING. DETERMINE WHY AND ADJUST VALUE AS REQUIRED. SEARCH "WAS ITALIC". //ELLIPSOID ADJUSTMENT //6378140.0 Ellipsoid is used in the NASA Calculator //WGS84 Ellipsoid is 6378137.0. Adjustments to the ellipsoid appear to effect eclipse seconds in fractions. //This can be modified if need to allow users to pass custom number with the Coordinate SetDatum() functions. //CURRENT RANGE 1601-2600. internal class SolarEclipseCalc { public static List> CalculateSolarEclipse(DateTime d, Double latRad, Double longRad) => Calculate(d, latRad, longRad, null); public static List CalculateSolarEclipse(DateTime d, Double latRad, Double longRad, Double[] events) { List> evs = Calculate(d, latRad, longRad, events); List deetsList = new List(); foreach (List ls in evs) { SolarEclipseDetails deets = new SolarEclipseDetails(ls); deetsList.Add(deets); } return deetsList; } public static List> CalculateSolarEclipse(DateTime d, Coordinate coord) => Calculate(d, coord.Latitude.ToRadians(), coord.Longitude.ToRadians(), null); private static List> Calculate(DateTime d, Double latRad, Double longRad, Double[] ev) { //Declare storage arrays Double[] obsvconst = new Double[7]; Double[] mid = new Double[41];//Check index to see if array needs to be this size Double[] c1 = new Double[41]; Double[] c2 = new Double[41]; Double[] c3 = new Double[41]; Double[] c4 = new Double[41]; Double[] el = ev ?? Eclipse.SolarData.SolarDateData(d); List> events = new List>(); ReadData(latRad, longRad, obsvconst); for (Int32 i = 0; i < el.Length; i += 28) { obsvconst[6] = i; GetAll(el, obsvconst, mid, c1, c2, c3, c4); // Is there an event... if (mid[39] > 0) { List values = new List { GetDate(el, mid, obsvconst) }; if (mid[39] == 1) { values.Add("P"); } else if (mid[39] == 2) { values.Add("A"); } else { values.Add("T"); } // Partial eclipse start if (c1[40] == 4) { values.Add("-"); values.Add(" "); } else { // Partial eclipse start time values.Add(GetTime(el, c1, obsvconst)); values.Add(GetAlt(c1)); } // Central eclipse time if (mid[39] > 1 && c2[40] != 4) { values.Add(GetTime(el, c2, obsvconst)); } else { values.Add("-"); } //Mid Time values.Add(GetTime(el, mid, obsvconst)); // Maximum eclipse alt values.Add(GetAlt(mid)); // Maximum eclipse azi values.Add(GetAzi(mid)); // Central eclipse ends if (mid[39] > 1 && c3[40] != 4) { values.Add(GetTime(el, c3, obsvconst)); } else { values.Add("-"); } // Partial eclipse ends if (c4[40] == 4) { values.Add("-"); values.Add(" "); } else { // Partial eclipse ends values.Add(GetTime(el, c4, obsvconst)); // ... sun alt values.Add(GetAlt(c4)); } // Eclipse magnitude values.Add(GetMagnitude(mid)); // Coverage values.Add(GetCoverage(mid)); // Central duration if (mid[39] > 1) { values.Add(GetDuration(mid, c2, c3)); } else { values.Add("-"); } events.Add(values); } } return events; } //Populates the obsvcont array private static void ReadData(Double latRad, Double longRad, Double[] obsvconst) { // Get the latitude obsvconst[0] = latRad; //// Get the longitude obsvconst[1] = -1 * longRad; //PASS REVERSE RADIAN. // Get the altitude obsvconst[2] = 100; //CHANGE TO ALLOW USER TO PASS. // Get the time zone obsvconst[3] = 0; //ALWAYS GMT // Get the observer's geocentric position Double tmp = Math.Atan(0.99664719 * Math.Tan(obsvconst[0])); obsvconst[4] = 0.99664719 * Math.Sin(tmp) + obsvconst[2] / 6378140.0 * Math.Sin(obsvconst[0]); obsvconst[5] = Math.Cos(tmp) + obsvconst[2] / 6378140.0 * Math.Cos(obsvconst[0]); } // Populate the c1, c2, mid, c3 and c4 arrays private static void GetAll(Double[] elements, Double[] obsvconst, Double[] mid, Double[] c1, Double[] c2, Double[] c3, Double[] c4) { GetMid(elements, obsvconst, mid); MidObservational(obsvconst, mid); if (mid[37] > 0.0) { Getc1c4(elements, obsvconst, mid, c1, c2, c3, c4); if (mid[36] < mid[29] || mid[36] < -mid[29]) { Getc2c3(elements, obsvconst, mid, c2, c3); mid[39] = mid[29] < 0.0 ? 3 : 2; Observational(c1, obsvconst, mid); Observational(c2, obsvconst, mid); Observational(c3, obsvconst, mid); Observational(c4, obsvconst, mid); c2[36] = 999.9; c3[36] = 999.9; // Calculate how much of the eclipse is above the horizon Double pattern = 0; if (c1[40] == 0) { pattern += 10000; } if (c2[40] == 0) { pattern += 1000; } if (mid[40] == 0) { pattern += 100; } if (c3[40] == 0) { pattern += 10; } if (c4[40] == 0) { pattern += 1; } // Now, time to make sure that all my Observational[39] and Observational[40] are OK if (pattern == 11110) { GetSunset(elements, c4, obsvconst); Observational(c4, obsvconst, mid); c4[40] = 3; } else if (pattern == 11100) { GetSunset(elements, c3, obsvconst); Observational(c3, obsvconst, mid); c3[40] = 3; CopyCircumstances(c3, c4); } else if (pattern == 11000) { c3[40] = 4; GetSunset(elements, mid, obsvconst); MidObservational(obsvconst, mid); mid[40] = 3; CopyCircumstances(mid, c4); } else if (pattern == 10000) { mid[39] = 1; GetSunset(elements, mid, obsvconst); MidObservational(obsvconst, mid); mid[40] = 3; CopyCircumstances(mid, c4); } else if (pattern == 1111) { GetSunrise(elements, c1, obsvconst); Observational(c1, obsvconst, mid); c1[40] = 2; } else if (pattern == 111) { GetSunrise(elements, c2, obsvconst); Observational(c2, obsvconst, mid); c2[40] = 2; CopyCircumstances(c2, c1); } else if (pattern == 11) { c2[40] = 4; GetSunrise(elements, mid, obsvconst); MidObservational(obsvconst, mid); mid[40] = 2; CopyCircumstances(mid, c1); } else if (pattern == 1) { mid[39] = 1; GetSunrise(elements, mid, obsvconst); MidObservational(obsvconst, mid); mid[40] = 2; CopyCircumstances(mid, c1); } else if (pattern == 0) { mid[39] = 0; } // There are other patterns, but those are the only ones we're covering! } else { mid[39] = 1; // Partial eclipse Double pattern = 0; Observational(c1, obsvconst, mid); Observational(c4, obsvconst, mid); if (c1[40] == 0) { pattern += 100; } if (mid[40] == 0) { pattern += 10; } if (c4[40] == 0) { pattern += 1; } if (pattern == 110) { GetSunset(elements, c4, obsvconst); Observational(c4, obsvconst, mid); c4[40] = 3; } else if (pattern == 100) { GetSunset(elements, mid, obsvconst); MidObservational(obsvconst, mid); mid[40] = 3; CopyCircumstances(mid, c4); } else if (pattern == 11) { GetSunrise(elements, c1, obsvconst); Observational(c1, obsvconst, mid); c1[40] = 2; } else if (pattern == 1) { GetSunrise(elements, mid, obsvconst); MidObservational(obsvconst, mid); mid[40] = 2; CopyCircumstances(mid, c1); } else if (pattern == 0) { mid[39] = 0; } // There are other patterns, but those are the only ones we're covering! } } else { mid[39] = 0; // No eclipse } // Magnitude for total and annular eclipse is moon/sun ratio if (mid[39] == 2 || mid[39] == 3) { mid[37] = mid[38]; } } // Calculate mid eclipse private static void GetMid(Double[] elements, Double[] obsvconst, Double[] mid) { Double iter, tmp; mid[0] = 0; mid[1] = 0.0; iter = 0; tmp = 1.0; _ = TimeLocDependent(elements, mid, obsvconst); while ((tmp > 0.000001 || tmp < -0.000001) && iter < 50) { tmp = (mid[24] * mid[26] + mid[25] * mid[27]) / mid[30]; mid[1] = mid[1] - tmp; iter++; _ = TimeLocDependent(elements, mid, obsvconst); } } // Populate the circumstances array with the time and location dependent circumstances private static Double[] TimeLocDependent(Double[] elements, Double[] circumstances, Double[] obsvconst) { Double index, type; _ = TimeDependent(elements, circumstances, obsvconst); index = obsvconst[6]; // Calculate h, sin h, cos h circumstances[16] = circumstances[7] - obsvconst[1] - elements[(Int32)index + 5] / 13713.44; circumstances[17] = Math.Sin(circumstances[16]); circumstances[18] = Math.Cos(circumstances[16]); // Calculate xi circumstances[19] = obsvconst[5] * circumstances[17]; // Calculate eta circumstances[20] = obsvconst[4] * circumstances[6] - obsvconst[5] * circumstances[18] * circumstances[5]; // Calculate zeta circumstances[21] = obsvconst[4] * circumstances[5] + obsvconst[5] * circumstances[18] * circumstances[6]; // Calculate dxi circumstances[22] = circumstances[13] * obsvconst[5] * circumstances[18]; // Calculate deta circumstances[23] = circumstances[13] * circumstances[19] * circumstances[5] - circumstances[21] * circumstances[12]; // Calculate u circumstances[24] = circumstances[2] - circumstances[19]; // Calculate v circumstances[25] = circumstances[3] - circumstances[20]; // Calculate a circumstances[26] = circumstances[10] - circumstances[22]; // Calculate b circumstances[27] = circumstances[11] - circumstances[23]; // Calculate l1' type = circumstances[0]; if (type == -2 || type == 0 || type == 2) { circumstances[28] = circumstances[8] - circumstances[21] * elements[26 + (Int32)index]; } // Calculate l2' if (type == -1 || type == 0 || type == 1) { circumstances[29] = circumstances[9] - circumstances[21] * elements[27 + (Int32)index]; } // Calculate n^2 circumstances[30] = circumstances[26] * circumstances[26] + circumstances[27] * circumstances[27]; return circumstances; } // Populate the circumstances array with the time-only dependent circumstances (x, y, d, m, ...) private static Double[] TimeDependent(Double[] elements, Double[] circumstances, Double[] obsvconst) { Double type, t, ans; t = circumstances[1]; Int32 index = (Int32)obsvconst[6]; // Calculate x ans = elements[9 + index] * t + elements[8 + index]; ans = ans * t + elements[7 + index]; ans = ans * t + elements[6 + index]; circumstances[2] = ans; // Calculate dx ans = 3.0 * elements[9 + index] * t + 2.0 * elements[8 + index]; ans = ans * t + elements[7 + index]; circumstances[10] = ans; // Calculate y ans = elements[13 + index] * t + elements[12 + index]; ans = ans * t + elements[11 + index]; ans = ans * t + elements[10 + index]; circumstances[3] = ans; // Calculate dy ans = 3.0 * elements[13 + index] * t + 2.0 * elements[12 + index]; ans = ans * t + elements[11 + index]; circumstances[11] = ans; // Calculate d ans = elements[16 + index] * t + elements[15 + index]; ans = ans * t + elements[14 + index]; ans = ans * Math.PI / 180.0; circumstances[4] = ans; // sin d and cos d circumstances[5] = Math.Sin(ans); circumstances[6] = Math.Cos(ans); // Calculate dd ans = 2.0 * elements[16 + index] * t + elements[15 + index]; ans = ans * Math.PI / 180.0; circumstances[12] = ans; // Calculate m ans = elements[19 + index] * t + elements[18 + index]; ans = ans * t + elements[17 + index]; if (ans >= 360.0) { ans -= 360.0; } ans = ans * Math.PI / 180.0; circumstances[7] = ans; // Calculate dm ans = 2.0 * elements[19 + index] * t + elements[18 + index]; ans = ans * Math.PI / 180.0; circumstances[13] = ans; // Calculate l1 and dl1 type = circumstances[0]; if (type == -2 || type == 0 || type == 2) { ans = elements[22 + index] * t + elements[21 + index]; ans = ans * t + elements[20 + index]; circumstances[8] = ans; circumstances[14] = 2.0 * elements[22 + index] * t + elements[21 + index]; } // Calculate l2 and dl2 if (type == -1 || type == 0 || type == 1) { ans = elements[25 + index] * t + elements[24 + index]; ans = ans * t + elements[23 + index]; circumstances[9] = ans; circumstances[15] = 2.0 * elements[25 + index] * t + elements[24 + index]; } return circumstances; } // Get the observational circumstances for mid eclipse private static void MidObservational(Double[] obsvconst, Double[] mid) { Observational(mid, obsvconst, mid); // Calculate m, magnitude and moon/sun mid[36] = Math.Sqrt(mid[24] * mid[24] + mid[25] * mid[25]); mid[37] = (mid[28] - mid[36]) / (mid[28] + mid[29]); mid[38] = (mid[28] - mid[29]) / (mid[28] + mid[29]); } // Get the observational circumstances private static void Observational(Double[] circumstances, Double[] obsvconst, Double[] mid) { Double contacttype, coslat, sinlat; // We are looking at an "external" contact UNLESS this is a total eclipse AND we are looking at // c2 or c3, in which case it is an INTERNAL contact! Note that if we are looking at mid eclipse, // then we may not have determined the type of eclipse (mid[39]) just yet! contacttype = circumstances[0] == 0 ? 1.0 : mid[39] == 3 && (circumstances[0] == -1 || circumstances[0] == 1) ? -1.0 : 1.0; // Calculate p circumstances[31] = Math.Atan2(contacttype * circumstances[24], contacttype * circumstances[25]); // Calculate alt sinlat = Math.Sin(obsvconst[0]); coslat = Math.Cos(obsvconst[0]); circumstances[32] = Math.Asin(circumstances[5] * sinlat + circumstances[6] * coslat * circumstances[18]); // Calculate q circumstances[33] = Math.Asin(coslat * circumstances[17] / Math.Cos(circumstances[32])); if (circumstances[20] < 0.0) { circumstances[33] = Math.PI - circumstances[33]; } // Calculate v circumstances[34] = circumstances[31] - circumstances[33]; // Calculate azi circumstances[35] = Math.Atan2(-1.0 * circumstances[17] * circumstances[6], circumstances[5] * coslat - circumstances[18] * sinlat * circumstances[6]); // Calculate visibility circumstances[40] = circumstances[32] > -0.00524 ? 0 : 1; } // Get C1 and C4 data // Entry conditions - // 1. The mid array must be populated // 2. The magnitude at mid eclipse must be > 0.0 private static void Getc1c4(Double[] elements, Double[] obsvconst, Double[] mid, Double[] c1, Double[] _1, Double[] _2, Double[] c4) { Double tmp, n; n = Math.Sqrt(mid[30]); tmp = mid[26] * mid[25] - mid[24] * mid[27]; tmp = tmp / n / mid[28]; tmp = Math.Sqrt(1.0 - tmp * tmp) * mid[28] / n; c1[0] = -2; c4[0] = 2; c1[1] = mid[1] - tmp; c4[1] = mid[1] + tmp; _ = C1c4iterate(elements, c1, obsvconst); _ = C1c4iterate(elements, c4, obsvconst); } // Iterate on C1 or C4 private static Double[] C1c4iterate(Double[] elements, Double[] circumstances, Double[] obsvconst) { Double sign, iter, tmp, n; _ = TimeLocDependent(elements, circumstances, obsvconst); sign = circumstances[0] < 0 ? -1.0 : 1.0; tmp = 1.0; iter = 0; while ((tmp > 0.000001 || tmp < -0.000001) && iter < 50) { n = Math.Sqrt(circumstances[30]); tmp = circumstances[26] * circumstances[25] - circumstances[24] * circumstances[27]; tmp = tmp / n / circumstances[28]; tmp = sign * Math.Sqrt(1.0 - tmp * tmp) * circumstances[28] / n; tmp = (circumstances[24] * circumstances[26] + circumstances[25] * circumstances[27]) / circumstances[30] - tmp; circumstances[1] = circumstances[1] - tmp; _ = TimeLocDependent(elements, circumstances, obsvconst); iter++; } return circumstances; } // Get C2 and C3 data // Entry conditions - // 1. The mid array must be populated // 2. There must be either a total or annular eclipse at the location! private static void Getc2c3(Double[] elements, Double[] obsvconst, Double[] mid, Double[] c2, Double[] c3) { Double tmp, n; n = Math.Sqrt(mid[30]); tmp = mid[26] * mid[25] - mid[24] * mid[27]; tmp = tmp / n / mid[29]; tmp = Math.Sqrt(1.0 - tmp * tmp) * mid[29] / n; c2[0] = -1; c3[0] = 1; if (mid[29] < 0.0) { c2[1] = mid[1] + tmp; c3[1] = mid[1] - tmp; } else { c2[1] = mid[1] - tmp; c3[1] = mid[1] + tmp; } _ = C2c3iterate(elements, c2, obsvconst, mid); _ = C2c3iterate(elements, c3, obsvconst, mid); } // Iterate on C2 or C3 private static Double[] C2c3iterate(Double[] elements, Double[] circumstances, Double[] obsvconst, Double[] mid) { Double sign, iter, tmp, n; _ = TimeLocDependent(elements, circumstances, obsvconst); sign = circumstances[0] < 0 ? -1.0 : 1.0; if (mid[29] < 0.0) { sign = -sign; } tmp = 1.0; iter = 0; while ((tmp > 0.000001 || tmp < -0.000001) && iter < 50) { n = Math.Sqrt(circumstances[30]); tmp = circumstances[26] * circumstances[25] - circumstances[24] * circumstances[27]; tmp = tmp / n / circumstances[29]; tmp = sign * Math.Sqrt(1.0 - tmp * tmp) * circumstances[29] / n; tmp = (circumstances[24] * circumstances[26] + circumstances[25] * circumstances[27]) / circumstances[30] - tmp; circumstances[1] = circumstances[1] - tmp; _ = TimeLocDependent(elements, circumstances, obsvconst); iter++; } return circumstances; } // Get the date of an event private static String GetDate(Double[] elements, Double[] circumstances, Double[] obsvconst) { String[] month = new String[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; Double t, jd, a, b, c, d, e, index; index = obsvconst[6]; // Calculate the JD for noon (TDT) the day before the day that contains T0 jd = Math.Floor(elements[(Int32)index] - elements[1 + (Int32)index] / 24.0); // Calculate the local time (ie the offset in hours since midnight TDT on the day containing T0). t = circumstances[1] + elements[1 + (Int32)index] - obsvconst[3] - (elements[4 + (Int32)index] - 0.5) / 3600.0; if (t < 0.0) { jd--; } if (t >= 24.0) { jd++; } if (jd >= 2299160.0) { a = Math.Floor((jd - 1867216.25) / 36524.25); a = jd + 1 + a - Math.Floor(a / 4.0); } else { a = jd; } b = a + 1525.0; c = Math.Floor((b - 122.1) / 365.25); d = Math.Floor(365.25 * c); e = Math.Floor((b - d) / 30.6001); d = b - d - Math.Floor(30.6001 * e); if (e < 13.5) { e -= 1; } else { e -= 13; } Double year; String ans; if (e > 2.5) { ans = c - 4716 + "-"; year = c - 4716; } else { ans = c - 4715 + "-"; year = c - 4715; } String m = month[(Int32)e - 1]; ans += m + "-"; if (d < 10) { ans += "0"; } ans += d; //Leap Year Integrity Check if (m == "Feb" && d == 29 && !DateTime.IsLeapYear((Int32)year)) { ans = year.ToString() + "-Mar-01"; } return ans; } // Calculate the time of sunset private static void GetSunset(Double[] elements, Double[] circumstances, Double[] obsvconst) => GetSunriset(elements, circumstances, 1.0, obsvconst); // Calculate the time of sunrise private static void GetSunrise(Double[] elements, Double[] circumstances, Double[] obsvconst) => GetSunriset(elements, circumstances, -1.0, obsvconst); // Calculate the time of sunrise or sunset private static void GetSunriset(Double[] elements, Double[] circumstances, Double riset, Double[] obsvconst) { Double h0, diff, iter; diff = 1.0; iter = 0; while (diff > 0.00001 || diff < -0.00001) { iter++; if (iter == 4) { return; } h0 = Math.Acos((Math.Sin(-0.00524) - Math.Sin(obsvconst[0]) * circumstances[5]) / Math.Cos(obsvconst[0]) / circumstances[6]); diff = (riset * h0 - circumstances[16]) / circumstances[13]; while (diff >= 12.0) { diff -= 24.0; } while (diff <= -12.0) { diff += 24.0; } circumstances[1] += diff; _ = TimeLocDependent(elements, circumstances, obsvconst); } } // Copy a set of circumstances private static void CopyCircumstances(Double[] circumstancesfrom, Double[] circumstancesto) { for (Int32 i = 1; i < 41; i++) { circumstancesto[i] = circumstancesfrom[i]; } } // Get the local time of an event private static String GetTime(Double[] elements, Double[] circumstances, Double[] obsvconst) { String ans = ""; Int32 index = (Int32)obsvconst[6]; Double t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[4 + index] - 0.5) / 3600.0; if (t < 0.0) { t += 24.0; } if (t >= 24.0) { t -= 24.0; } if (t < 10.0) { ans += "0"; } ans = ans + Math.Floor(t) + ":"; t = t * 60.0 - 60.0 * Math.Floor(t); if (t < 10.0) { ans += "0"; } ans += Math.Floor(t); if (circumstances[40] <= 1) { // not sunrise or sunset ans += ":"; t = t * 60.0 - 60.0 * Math.Floor(t); if (t < 10.0) { ans += "0"; } ans += Math.Floor(t); } if (circumstances[40] == 1) { //WAS ITALIC return ans; } else if (circumstances[40] == 2) { //Rise (CHANGED FROM NASA CALC THE INDICATES (r) WITH STRING, INVESTIGATE REMOVAL) return ans; } else if (circumstances[40] == 3) { //Set (CHANGED FROM NASA CALC THE INDICATES (s) WITH STRING, INVESTIGATE REMOVAL) return ans; } else { return ans; } } // Get the altitude private static String GetAlt(Double[] circumstances) { Double t; if (circumstances[40] == 2) { return "0(r)"; } if (circumstances[40] == 3) { return "0(s)"; } if (circumstances[32] < 0.0 && circumstances[32] >= -0.00524) { // Crude correction for refraction (and for consistency's sake) t = 0.0; } else { t = circumstances[32] * 180.0 / Math.PI; } String ans; if (t < 0.0) { ans = "-"; t = -t; } else { ans = ""; } t = Math.Floor(t + 0.5); if (t < 10.0) { ans += "0"; } ans += t; if (circumstances[40] == 1) { //WAS ITALIC return ans; } else { return ans; } } // Get the azimuth private static String GetAzi(Double[] circumstances) { String ans = ""; Double t = circumstances[35] * 180.0 / Math.PI; if (t < 0.0) { t += 360.0; } if (t >= 360.0) { t -= 360.0; } t = Math.Floor(t + 0.5); if (t < 100.0) { ans += "0"; } if (t < 10.0) { ans += "0"; } ans += t; if (circumstances[40] == 1) { //WAS ITALIC return ans; } else { return ans; } } // Get the magnitude private static String GetMagnitude(Double[] mid) { Double a = Math.Floor(1000.0 * mid[37] + 0.5) / 1000.0; String ans = a.ToString(); if (mid[40] == 1) { return ans; } if (mid[40] == 2) { ans = a.ToString() + "(r)"; } if (mid[40] == 3) { ans = a.ToString() + "(s)"; } return ans; } // Get the coverage private static String GetCoverage(Double[] mid) { Double a = 0, b, c; String ans; if (mid[37] <= 0.0) { ans = "0.0"; } else if (mid[37] >= 1.0) { ans = "1.000"; } else { if (mid[39] == 2) { c = mid[38] * mid[38]; } else { c = Math.Acos((mid[28] * mid[28] + mid[29] * mid[29] - 2.0 * mid[36] * mid[36]) / (mid[28] * mid[28] - mid[29] * mid[29])); b = Math.Acos((mid[28] * mid[29] + mid[36] * mid[36]) / mid[36] / (mid[28] + mid[29])); a = Math.PI - b - c; c = (mid[38] * mid[38] * a + b - mid[38] * Math.Sin(c)) / Math.PI; } a = Math.Floor(1000.0 * c + 0.5) / 1000.0; ans = a.ToString(); } if (mid[40] == 1) { //WAS ITALIC return ans; } if (mid[40] == 2) { ans = a.ToString() + "(r)"; } if (mid[40] == 3) { ans = a + "(s)"; } return ans; } // Get the duration in mm:ss.s format // Adapted from code written by Stephen McCann - 27/04/2001 private static String GetDuration(Double[] mid, Double[] c2, Double[] c3) { Double tmp; String ans; tmp = c3[40] == 4 ? mid[1] - c2[1] : c2[40] == 4 ? c3[1] - mid[1] : c3[1] - c2[1]; if (tmp < 0.0) { tmp += 24.0; } else if (tmp >= 24.0) { tmp -= 24.0; } tmp = tmp * 60.0 - 60.0 * Math.Floor(tmp) + 0.05 / 60.0; ans = Math.Floor(tmp) + "m"; tmp = tmp * 60.0 - 60.0 * Math.Floor(tmp); if (tmp < 10.0) { ans += "0"; } ans += Math.Floor(tmp) + "s"; return ans; } } }