/// <summary> /// Calculate the three dimensional geodetic measurement between two positions /// measured in reference to a specified ellipsoid. /// /// This calculation is performed by first computing a new ellipsoid by expanding or contracting /// the reference ellipsoid such that the new ellipsoid passes through the average elevation /// of the two positions. A geodetic curve across the new ellisoid is calculated. The /// point-to-point distance is calculated as the hypotenuse of a right triangle where the length /// of one side is the ellipsoidal distance and the other is the difference in elevation. /// </summary> /// <param name="refEllipsoid">reference ellipsoid to use</param> /// <param name="start">starting position</param> /// <param name="end">ending position</param> /// <returns></returns> public GeodeticMeasurement CalculateGeodeticMeasurement(Ellipsoid refEllipsoid, GlobalPosition start, GlobalPosition end) { // get the coordinates GlobalCoordinates startCoords = start.Coordinates; GlobalCoordinates endCoords = end.Coordinates; // calculate elevation differences double elev1 = start.Elevation; double elev2 = end.Elevation; double elev12 = (elev1 + elev2) / 2.0; // calculate latitude differences double phi1 = startCoords.Latitude.Radians; double phi2 = endCoords.Latitude.Radians; double phi12 = (phi1 + phi2) / 2.0; // calculate a new ellipsoid to accommodate average elevation double refA = refEllipsoid.SemiMajorAxis; double f = refEllipsoid.Flattening; double a = refA + elev12 * (1.0 + f * Math.Sin(phi12)); Ellipsoid ellipsoid = Ellipsoid.FromAAndF(a, f); // calculate the curve at the average elevation GeodeticCurve averageCurve = CalculateGeodeticCurve(ellipsoid, startCoords, endCoords); // return the measurement return new GeodeticMeasurement(averageCurve, elev2 - elev1); }
/// <summary> /// Calculate the destination and final bearing after traveling a specified /// distance, and a specified starting bearing, for an initial location. /// This is the solution to the direct geodetic problem. /// </summary> /// <param name="ellipsoid">reference ellipsoid to use</param> /// <param name="start">starting location</param> /// <param name="startBearing">starting bearing (degrees)</param> /// <param name="distance">distance to travel (meters)</param> /// <param name="endBearing">bearing at destination (degrees)</param> /// <returns></returns> public GlobalCoordinates CalculateEndingGlobalCoordinates(Ellipsoid ellipsoid, GlobalCoordinates start, Angle startBearing, double distance, out Angle endBearing) { double a = ellipsoid.SemiMajorAxis; double b = ellipsoid.SemiMinorAxis; double aSquared = a * a; double bSquared = b * b; double f = ellipsoid.Flattening; double phi1 = start.Latitude.Radians; double alpha1 = startBearing.Radians; double cosAlpha1 = Math.Cos(alpha1); double sinAlpha1 = Math.Sin(alpha1); double s = distance; double tanU1 = (1.0 - f) * Math.Tan(phi1); double cosU1 = 1.0 / Math.Sqrt(1.0 + tanU1 * tanU1); double sinU1 = tanU1 * cosU1; // eq. 1 double sigma1 = Math.Atan2(tanU1, cosAlpha1); // eq. 2 double sinAlpha = cosU1 * sinAlpha1; double sin2Alpha = sinAlpha * sinAlpha; double cos2Alpha = 1 - sin2Alpha; double uSquared = cos2Alpha * (aSquared - bSquared) / bSquared; // eq. 3 double A = 1 + (uSquared / 16384) * (4096 + uSquared * (-768 + uSquared * (320 - 175 * uSquared))); // eq. 4 double B = (uSquared / 1024) * (256 + uSquared * (-128 + uSquared * (74 - 47 * uSquared))); // iterate until there is a negligible change in sigma double deltaSigma; double sOverbA = s / (b * A); double sigma = sOverbA; double sinSigma; double prevSigma = sOverbA; double sigmaM2; double cosSigmaM2; double cos2SigmaM2; for (; ; ) { // eq. 5 sigmaM2 = 2.0 * sigma1 + sigma; cosSigmaM2 = Math.Cos(sigmaM2); cos2SigmaM2 = cosSigmaM2 * cosSigmaM2; sinSigma = Math.Sin(sigma); double cosSignma = Math.Cos(sigma); // eq. 6 deltaSigma = B * sinSigma * (cosSigmaM2 + (B / 4.0) * (cosSignma * (-1 + 2 * cos2SigmaM2) - (B / 6.0) * cosSigmaM2 * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM2))); // eq. 7 sigma = sOverbA + deltaSigma; // break after converging to tolerance if (Math.Abs(sigma - prevSigma) < 0.0000000000001) break; prevSigma = sigma; } sigmaM2 = 2.0 * sigma1 + sigma; cosSigmaM2 = Math.Cos(sigmaM2); cos2SigmaM2 = cosSigmaM2 * cosSigmaM2; double cosSigma = Math.Cos(sigma); sinSigma = Math.Sin(sigma); // eq. 8 double phi2 = Math.Atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1, (1.0 - f) * Math.Sqrt(sin2Alpha + Math.Pow(sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1, 2.0))); // eq. 9 // This fixes the pole crossing defect spotted by Matt Feemster. When a path // passes a pole and essentially crosses a line of latitude twice - once in // each direction - the longitude calculation got messed up. Using Atan2 // instead of Atan fixes the defect. The change is in the next 3 lines. //double tanLambda = sinSigma * sinAlpha1 / (cosU1 * cosSigma - sinU1*sinSigma*cosAlpha1); //double lambda = Math.Atan(tanLambda); double lambda = Math.Atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1); // eq. 10 double C = (f / 16) * cos2Alpha * (4 + f * (4 - 3 * cos2Alpha)); // eq. 11 double L = lambda - (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cosSigmaM2 + C * cosSigma * (-1 + 2 * cos2SigmaM2))); // eq. 12 double alpha2 = Math.Atan2(sinAlpha, -sinU1 * sinSigma + cosU1 * cosSigma * cosAlpha1); // build result Angle latitude = new Angle(); Angle longitude = new Angle(); latitude.Radians = phi2; longitude.Radians = start.Longitude.Radians + L; endBearing = new Angle(); endBearing.Radians = alpha2; return new GlobalCoordinates(latitude, longitude); }
/// <summary> /// Calculate the destination after traveling a specified distance, and a /// specified starting bearing, for an initial location. This is the /// solution to the direct geodetic problem. /// </summary> /// <param name="ellipsoid">reference ellipsoid to use</param> /// <param name="start">starting location</param> /// <param name="startBearing">starting bearing (degrees)</param> /// <param name="distance">distance to travel (meters)</param> /// <returns></returns> public GlobalCoordinates CalculateEndingGlobalCoordinates(Ellipsoid ellipsoid, GlobalCoordinates start, Angle startBearing, double distance) { Angle endBearing = new Angle(); return CalculateEndingGlobalCoordinates(ellipsoid, start, startBearing, distance, out endBearing); }
/// <summary> /// Calculate the geodetic curve between two points on a specified reference ellipsoid. /// This is the solution to the inverse geodetic problem. /// </summary> /// <param name="ellipsoid">reference ellipsoid to use</param> /// <param name="start">starting coordinates</param> /// <param name="end">ending coordinates </param> /// <returns></returns> public GeodeticCurve CalculateGeodeticCurve(Ellipsoid ellipsoid, GlobalCoordinates start, GlobalCoordinates end) { // // All equation numbers refer back to Vincenty's publication: // See http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf // // get constants double a = ellipsoid.SemiMajorAxis; double b = ellipsoid.SemiMinorAxis; double f = ellipsoid.Flattening; // get parameters as radians double phi1 = start.Latitude.Radians; double lambda1 = start.Longitude.Radians; double phi2 = end.Latitude.Radians; double lambda2 = end.Longitude.Radians; // calculations double a2 = a * a; double b2 = b * b; double a2b2b2 = (a2 - b2) / b2; double omega = lambda2 - lambda1; double tanphi1 = Math.Tan(phi1); double tanU1 = (1.0 - f) * tanphi1; double U1 = Math.Atan(tanU1); double sinU1 = Math.Sin(U1); double cosU1 = Math.Cos(U1); double tanphi2 = Math.Tan(phi2); double tanU2 = (1.0 - f) * tanphi2; double U2 = Math.Atan(tanU2); double sinU2 = Math.Sin(U2); double cosU2 = Math.Cos(U2); double sinU1sinU2 = sinU1 * sinU2; double cosU1sinU2 = cosU1 * sinU2; double sinU1cosU2 = sinU1 * cosU2; double cosU1cosU2 = cosU1 * cosU2; // eq. 13 double lambda = omega; // intermediates we'll need to compute 's' double A = 0.0; double B = 0.0; double sigma = 0.0; double deltasigma = 0.0; double lambda0; bool converged = false; for (int i = 0; i < 20; i++) { lambda0 = lambda; double sinlambda = Math.Sin(lambda); double coslambda = Math.Cos(lambda); // eq. 14 double sin2sigma = (cosU2 * sinlambda * cosU2 * sinlambda) + Math.Pow(cosU1sinU2 - sinU1cosU2 * coslambda, 2.0); double sinsigma = Math.Sqrt(sin2sigma); // eq. 15 double cossigma = sinU1sinU2 + (cosU1cosU2 * coslambda); // eq. 16 sigma = Math.Atan2(sinsigma, cossigma); // eq. 17 Careful! sin2sigma might be almost 0! double sinalpha = (sin2sigma == 0) ? 0.0 : cosU1cosU2 * sinlambda / sinsigma; double alpha = Math.Asin(sinalpha); double cosalpha = Math.Cos(alpha); double cos2alpha = cosalpha * cosalpha; // eq. 18 Careful! cos2alpha might be almost 0! double cos2sigmam = cos2alpha == 0.0 ? 0.0 : cossigma - 2 * sinU1sinU2 / cos2alpha; double u2 = cos2alpha * a2b2b2; double cos2sigmam2 = cos2sigmam * cos2sigmam; // eq. 3 A = 1.0 + u2 / 16384 * (4096 + u2 * (-768 + u2 * (320 - 175 * u2))); // eq. 4 B = u2 / 1024 * (256 + u2 * (-128 + u2 * (74 - 47 * u2))); // eq. 6 deltasigma = B * sinsigma * (cos2sigmam + B / 4 * (cossigma * (-1 + 2 * cos2sigmam2) - B / 6 * cos2sigmam * (-3 + 4 * sin2sigma) * (-3 + 4 * cos2sigmam2))); // eq. 10 double C = f / 16 * cos2alpha * (4 + f * (4 - 3 * cos2alpha)); // eq. 11 (modified) lambda = omega + (1 - C) * f * sinalpha * (sigma + C * sinsigma * (cos2sigmam + C * cossigma * (-1 + 2 * cos2sigmam2))); // see how much improvement we got double change = Math.Abs((lambda - lambda0) / lambda); if ((i > 1) && (change < 0.0000000000001)) { converged = true; break; } } // eq. 19 double s = b * A * (sigma - deltasigma); Angle alpha1; Angle alpha2; // didn't converge? must be N/S if (!converged) { if (phi1 > phi2) { alpha1 = Angle.Angle180; alpha2 = Angle.Zero; } else if (phi1 < phi2) { alpha1 = Angle.Zero; alpha2 = Angle.Angle180; } else { alpha1 = new Angle(Double.NaN); alpha2 = new Angle(Double.NaN); } } // else, it converged, so do the math else { double radians; alpha1 = new Angle(); alpha2 = new Angle(); // eq. 20 radians = Math.Atan2(cosU2 * Math.Sin(lambda), (cosU1sinU2 - sinU1cosU2 * Math.Cos(lambda))); if (radians < 0.0) radians += TwoPi; alpha1.Radians = radians; // eq. 21 radians = Math.Atan2(cosU1 * Math.Sin(lambda), (-sinU1cosU2 + cosU1sinU2 * Math.Cos(lambda))) + Math.PI; if (radians < 0.0) radians += TwoPi; alpha2.Radians = radians; } if (alpha1 >= 360.0) alpha1 -= 360.0; if (alpha2 >= 360.0) alpha2 -= 360.0; return new GeodeticCurve(s, alpha1, alpha2); }
public override void OnRender(Graphics g) { Pen MyPen = new Pen(new SolidBrush(LabelAttributes.TargetColor), LabelAttributes.TargetSize); MyPen.DashStyle = LabelAttributes.TargetStyle; // Draw AC Symbol g.DrawRectangle(MyPen, LocalPosition.X - 5, LocalPosition.Y - 5, 10, 10); AC_SYMB_START_X = LocalPosition.X - 5; AC_SYMB_START_Y = LocalPosition.Y - 5; ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // Here handle drawing of Range/Bearing & SEP tool if (TargetToMonitor != -1) { Point StartPosition = new Point(LocalPosition.X, LocalPosition.Y); Point EndPosition = DynamicDisplayBuilder.GetTargetPositionByIndex(TargetToMonitor); g.DrawLine(new Pen(Brushes.Yellow, 1), StartPosition, EndPosition); // select a reference elllipsoid Ellipsoid reference = Ellipsoid.WGS84; // instantiate the calculator GeodeticCalculator geoCalc = new GeodeticCalculator(); GlobalPosition Start = new GlobalPosition(new GlobalCoordinates(this.Position.Lat, this.Position.Lng)); PointLatLng End_LatLng = FormMain.FromLocalToLatLng(EndPosition.X, EndPosition.Y); GlobalPosition End = new GlobalPosition(new GlobalCoordinates(End_LatLng.Lat, End_LatLng.Lng)); GeodeticMeasurement GM = geoCalc.CalculateGeodeticMeasurement(reference, End, Start); //////////////////////////////////////////////////////////////////////////////////////////// // Handle SEP Tool double TRK1_SPD = 0.0, TRK2_SPD = 0.0; double TRK1_AZ = 0.0, TRK2_AZ = 0.0; bool Sep_Data_Is_Valid = true; if (!double.TryParse(CALC_GSPD_STRING, out TRK1_SPD)) { if (!double.TryParse(DAP_GSPD, out TRK1_SPD)) { Sep_Data_Is_Valid = false; } } if (!double.TryParse(DynamicDisplayBuilder.GetTarget_CALC_GSPD_ByIndex(TargetToMonitor), out TRK2_SPD)) { if (!double.TryParse(DynamicDisplayBuilder.GetTarget_DAP_GSPD_ByIndex(TargetToMonitor), out TRK2_SPD)) { Sep_Data_Is_Valid = false; } } if (!double.TryParse(CALC_HDG_STRING, out TRK1_AZ)) { if (!double.TryParse(TRK, out TRK1_AZ)) { if (!double.TryParse(DAP_HDG, out TRK1_AZ)) { Sep_Data_Is_Valid = false; } } } if (!double.TryParse(DynamicDisplayBuilder.GetTarget_CALC_HDG_ByIndex(TargetToMonitor), out TRK2_AZ)) { if (!double.TryParse(DynamicDisplayBuilder.GetTargetTRKByIndex(TargetToMonitor), out TRK2_AZ)) { if (!double.TryParse(DynamicDisplayBuilder.GetTargetM_HDGByIndex(TargetToMonitor), out TRK2_AZ)) { Sep_Data_Is_Valid = false; } } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // If all the necessary data is avilable // then pass it on to the SEP tool calculator // and then draw the result string SepToolActive = "N/A"; if (Sep_Data_Is_Valid) { SEP_Tool_Calculator SepTool = new SEP_Tool_Calculator(Start, End, TRK1_SPD, TRK2_SPD, TRK1_AZ, TRK2_AZ, 20); SEP_Tool_Calculator.OutData Sep_Tool_Data = SepTool.GetResult(); if (Sep_Tool_Data.Is_Converging) { g.DrawRectangle(new Pen(Brushes.Yellow, LabelAttributes.TargetSize), Sep_Tool_Data.Track_1_Pos_Min.X - 5, Sep_Tool_Data.Track_1_Pos_Min.Y - 5, 10, 10); g.DrawRectangle(new Pen(Brushes.Yellow, LabelAttributes.TargetSize), Sep_Tool_Data.Track_2_Pos_Min.X - 5, Sep_Tool_Data.Track_2_Pos_Min.Y - 5, 10, 10); g.DrawLine(new Pen(Brushes.Yellow, LabelAttributes.TargetSize), new Point(Sep_Tool_Data.Track_1_Pos_Min.X, Sep_Tool_Data.Track_1_Pos_Min.Y), new Point(StartPosition.X, StartPosition.Y)); g.DrawLine(new Pen(Brushes.Yellow, LabelAttributes.TargetSize), new Point(Sep_Tool_Data.Track_2_Pos_Min.X, Sep_Tool_Data.Track_2_Pos_Min.Y), new Point(EndPosition.X, EndPosition.Y)); TimeSpan T = TimeSpan.FromSeconds(Sep_Tool_Data.SecondsToMinimum); SepToolActive = "min d:" + Math.Round(Sep_Tool_Data.MinDistance, 1).ToString() + "/" + T.Minutes.ToString() + ":" + T.Seconds.ToString(); } } // Now compute position half way between two points. double distance = GM.PointToPointDistance / 2.0; if (distance > 0.0) { GlobalCoordinates GC = geoCalc.CalculateEndingGlobalCoordinates(reference, new GlobalCoordinates(End_LatLng.Lat, End_LatLng.Lng), GM.Azimuth, distance); GPoint GP = FormMain.FromLatLngToLocal(new PointLatLng(GC.Latitude.Degrees, GC.Longitude.Degrees)); double Distane_NM = 0.00053996 * GM.PointToPointDistance; g.DrawString(Math.Round(GM.Azimuth.Degrees).ToString() + "°/" + Math.Round(Distane_NM, 1).ToString() + "nm", new Font(FontFamily.GenericSansSerif, 9), Brushes.Yellow, new PointF(GP.X, GP.Y)); if (Sep_Data_Is_Valid && SepToolActive != "N/A") { g.DrawString(SepToolActive, new Font(FontFamily.GenericSansSerif, 9), Brushes.Yellow, new PointF(GP.X, GP.Y + 15)); } } } // Here handle history points // First draw all previous history points int Number_of_Points_Drawn = 0; for (int Index = HistoryPoints.Count - 2; Index >= 0; Index--) { if (Number_of_Points_Drawn < Properties.Settings.Default.HistoryPoints) { HistoryPointsType I = HistoryPoints.ElementAt(Index); GPoint MarkerPositionLocal = FormMain.gMapControl.FromLatLngToLocal(new PointLatLng(I.LatLong.Lat, I.LatLong.Lng)); g.DrawEllipse(MyPen, MarkerPositionLocal.X, MarkerPositionLocal.Y, 3, 3); Number_of_Points_Drawn++; } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Here draw speed vector // // Find out what data should be used for speed vector? IAS, TAS, GSPD, MACH? if ((DataItemValidator(CALC_HDG_STRING) || DataItemValidator(DAP_HDG) || DataItemValidator(TRK)) && (DataItemValidator(DAP_GSPD) || DataItemValidator(CALC_GSPD_STRING))) { double Azimuth = 0.0; double Range = 0.0; if (DataItemValidator(CALC_GSPD_STRING)) { Range = double.Parse(CALC_GSPD_STRING); } else { Range = double.Parse(DAP_GSPD); } if (DataItemValidator(CALC_HDG_STRING)) { Azimuth = double.Parse(CALC_HDG_STRING); } else if (DataItemValidator(TRK)) { Azimuth = double.Parse(TRK); } else { Azimuth = double.Parse(DAP_HDG); } Range = (Range / 60) * (double)Properties.Settings.Default.SpeedVector; GeoCordSystemDegMinSecUtilities.LatLongClass ResultPosition = GeoCordSystemDegMinSecUtilities.CalculateNewPosition(new GeoCordSystemDegMinSecUtilities.LatLongClass(Position.Lat, Position.Lng), (double)Range, (double)Azimuth); GPoint MarkerPositionLocal = FormMain.gMapControl.FromLatLngToLocal(new PointLatLng(ResultPosition.GetLatLongDecimal().LatitudeDecimal, ResultPosition.GetLatLongDecimal().LongitudeDecimal)); g.DrawLine(MyPen, new Point(LocalPosition.X, LocalPosition.Y), new Point(MarkerPositionLocal.X, MarkerPositionLocal.Y)); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MyPen = new Pen(new SolidBrush(LabelAttributes.LineColor), LabelAttributes.LineWidth); MyPen.DashStyle = LabelAttributes.LineStyle; // Draw leader line g.DrawLine(MyPen, new Point(LocalPosition.X, LocalPosition.Y), new Point(LocalPosition.X - LabelOffset.X, LocalPosition.Y - LabelOffset.Y)); // Draw label box Point LabelStartPosition = GetLabelStartingPoint(); // Recalculate Label Width each cycle to adjust for the possible changes in the number of lines // and changes in the text size LabelHeight = 0; // Draw ModeA and coast indicator g.DrawString(ModeA_CI_STRING, ModeA_CI_FONT, ModeA_CI_BRUSH, LabelStartPosition.X + ModeA_CI_OFFSET.X, LabelStartPosition.Y + SpacingIndex); LabelHeight = LabelHeight + (int)ModeA_CI_FONT.Size + SpacingIndex * 2; if (CALLSIGN_STRING != "--------") { // Draw CALLSIGN g.DrawString(CALLSIGN_STRING, CALLSIGN_FONT, CALLSIGN_BRUSH, LabelStartPosition.X + CALLSIGN_OFFSET.X, LabelStartPosition.Y + LabelHeight); LabelHeight = LabelHeight + (int)CALLSIGN_FONT.Size + SpacingIndex * 2; } // Draw ModeC g.DrawString(ModeC_STRING, ModeC_FONT, ModeC_BRUSH, LabelStartPosition.X + ModeC_OFFSET.X, LabelStartPosition.Y + LabelHeight); // Draw CFL on the same line if (ModeC_STRING == null) { ModeC_STRING = "---"; } CFL_OFFSET.X = ModeC_STRING.Length * (int)ModeC_FONT.Size; CFL_OFFSET.Y = LabelStartPosition.Y + LabelHeight; g.DrawString(CFL_STRING, CFL_FONT, CFL_BRUSH, LabelStartPosition.X + CFL_OFFSET.X, CFL_OFFSET.Y); CFL_START_X = LabelStartPosition.X + CFL_OFFSET.X; CFL_START_Y = CFL_OFFSET.Y; // Draw GSPD on the same line GSPD_OFFSET.X = (ModeC_STRING.Length * (int)ModeC_FONT.Size) + (CFL_STRING.Length * (int)CFL_FONT.Size); GSPD_OFFSET.Y = LabelStartPosition.Y + LabelHeight; if (CALC_GSPD_STRING != " ---") { g.DrawString(CALC_GSPD_STRING, GSPD_FONT, GSPD_BRUSH, LabelStartPosition.X + GSPD_OFFSET.X, GSPD_OFFSET.Y); } else if (DAP_GSPD != "N/A") { g.DrawString(DAP_GSPD, GSPD_FONT, GSPD_BRUSH, LabelStartPosition.X + GSPD_OFFSET.X, GSPD_OFFSET.Y); } else { g.DrawString(" ---", GSPD_FONT, GSPD_BRUSH, LabelStartPosition.X + GSPD_OFFSET.X, GSPD_OFFSET.Y); } GSPD_START_X = LabelStartPosition.X + GSPD_OFFSET.X; GSPD_START_Y = GSPD_OFFSET.Y; LabelHeight = LabelHeight + (int)GSPD_FONT.Size + SpacingIndex * 2; if (ShowLabelBox == true) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // DRAW Assigned HDG, SPD and ROC ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // HDG g.DrawString(A_HDG_STRING, A_HDG_FONT, A_HDG_BRUSH, LabelStartPosition.X + A_HDG_OFFSET.X, LabelStartPosition.Y + LabelHeight); HDG_START_X = LabelStartPosition.X + A_HDG_OFFSET.X; HDG_START_Y = LabelStartPosition.Y + LabelHeight; // SPD A_SPD_OFFSET.X = A_HDG_STRING.Length * (int)A_HDG_FONT.Size; A_SPD_OFFSET.Y = LabelStartPosition.Y + LabelHeight; g.DrawString(A_SPD_STRING, A_SPD_FONT, A_SPD_BRUSH, LabelStartPosition.X + A_SPD_OFFSET.X, A_SPD_OFFSET.Y); SPD_START_X = LabelStartPosition.X + A_SPD_OFFSET.X; SPD_START_Y = A_SPD_OFFSET.Y; // ROC //A_ROC_OFFSET.X = A_SPD_OFFSET.X + A_SPD_OFFSET.X + A_SPD_STRING.Length * (int)A_SPD_FONT.Size; //A_ROC_OFFSET.Y = LabelStartPosition.Y + LabelHeight; // g.DrawString(A_ROC_STRING, A_ROC_FONT, A_ROC_BRUSH, LabelStartPosition.X + A_ROC_OFFSET.X, A_ROC_OFFSET.Y); LabelHeight = LabelHeight + (int)A_SPD_FONT.Size + SpacingIndex * 2; // Add the final spacing index and draw the box LabelHeight = LabelHeight + SpacingIndex * 2; g.DrawRectangle(MyPen, LabelStartPosition.X, LabelStartPosition.Y, LabelWidth, LabelHeight); } }