Click here to Skip to main content
15,896,726 members
Articles / Programming Languages / Java

NMEA 0183 sentence parser/builder

Rate me:
Please Sign up or sign in to vote.
4.78/5 (25 votes)
10 Dec 2013CPOL6 min read 249.3K   15K   97  
Library for working with NMEA0183 devices
using System;using System.Drawing;
using System.Windows.Forms;

namespace GNSSView
{
    // Code by Aleksandr Dikarev, dikarev-aleksandr@yandex.ru
    public struct GeoCoordinate2D
    {
        public double Latitude;
        public double Longitude;
    }

    public partial class GeoPlot : UserControl
    {
        #region Properties

        int maxPoints = 10;
        FixedSizeLIFO<GeoCoordinate2D> points;

        Pen pointPen = new Pen(Brushes.Blue, 2.0f);
        Pen gridPen = new Pen(Brushes.Black, 1.0f);

        #endregion

        #region Constructor

        public GeoPlot()
        {
            InitializeComponent();
        }

        #endregion

        #region Methods

        public void Init(int trajectoryLength)
        {
            maxPoints = trajectoryLength;
            points = new FixedSizeLIFO<GeoCoordinate2D>(maxPoints);
        }

        public void AddPoint(GeoCoordinate2D newPoint)
        {
            points.Add(newPoint);
        }

        public static void GetCurveLengths(out double byMeridian, out double byParallel, double lat1, double lon1, double lat2, double lon2)
        {                        
            double majAxis = 6378137.0;

            double invFlt = 298.257223563;
            double flt = 1 / invFlt;
            double minAxis = majAxis * (1 - flt);
            double ellE2 = 1 - minAxis * minAxis / majAxis / majAxis;
                                 
            double avrLatitude = (lat2 + lat1) / 2.0;
            
            double W = Math.Sqrt(1 - ellE2 * Math.Sin(avrLatitude * Math.PI / 180) * Math.Sin(avrLatitude * Math.PI / 180));
            double ecrM = majAxis * (1 - ellE2) / W / W / W;
            double ecrN = majAxis / W;

            byMeridian = ecrM * (lat2 - lat1) * Math.PI / 180.0;
            byParallel = ecrN * Math.Cos(avrLatitude * Math.PI / 180) * (lon2 - lon1) * Math.PI / 180.0;
        }

        private static double GetDistance2DM(double lat1, double lon1, double lat2, double lon2)
        {
            double xl, yl;
            GetCurveLengths(out xl, out yl, lat1, lon1, lat2, lon2);

            return Math.Sqrt(xl * xl + yl * yl);
        }

        #endregion
        
        #region Handlers

        private void GeoPlot_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

            if ((points != null) && (!e.ClipRectangle.IsEmpty))
            {
                var items = points.ToArray();

                if (items.Length > 1)
                {
                    double meanLat = items[0].Latitude;
                    double meanLon = items[0].Longitude;
                    
                    double farestLat = 0.0;
                    double farestLon = 0.0;

                    for (int i = 0; i < items.Length; i++)
                    {
                        if (Math.Abs(items[i].Latitude - meanLat) > farestLat)
                            farestLat = Math.Abs(items[i].Latitude - meanLat);

                        if (Math.Abs(items[i].Longitude - meanLon) > farestLon)
                            farestLon = Math.Abs(items[i].Longitude - meanLon);
                    }

                    double farestDist = Math.Max(farestLat, farestLon);


                    if (farestDist < double.Epsilon)
                        farestDist = 0.000001;

                    double xScale = e.Graphics.ClipBounds.Width / (farestDist * 2.0f);
                    double yScale = e.Graphics.ClipBounds.Height / (farestDist * 2.0f);

                    float scale = (float)Math.Min(xScale, yScale);

                    e.Graphics.TranslateTransform(e.ClipRectangle.Width / 2.0f, e.ClipRectangle.Height / 2.0f);

                    float fDist = Math.Abs((float)farestDist * 0.75f);
                    double fDistM = GetDistance2DM(meanLat, meanLon, meanLat + fDist, meanLon + fDist);
                    float fDistScaled = (float)(fDist * scale);

                    e.Graphics.DrawLine(gridPen, -fDistScaled, -4, -fDistScaled, 4);
                    e.Graphics.DrawLine(gridPen, fDistScaled, -4, fDistScaled, 4);
                    e.Graphics.DrawLine(gridPen, -4, -fDistScaled, 4, -fDistScaled);
                    e.Graphics.DrawLine(gridPen, -4, fDistScaled, 4, fDistScaled);

                    var fDistMLbl = fDistM.ToString("0.0 m");
                    var fDistMLblSize = e.Graphics.MeasureString(fDistMLbl, this.Font);

                    e.Graphics.DrawString(fDistMLbl, this.Font, Brushes.Black,
                        -fDistScaled - fDistMLblSize.Width / 2, -fDistMLblSize.Height - 2);

                    e.Graphics.DrawString(fDistMLbl, this.Font, Brushes.Black,
                        fDistScaled - fDistMLblSize.Width / 2, -fDistMLblSize.Height - 2);

                    e.Graphics.DrawString(fDistMLbl, this.Font, Brushes.Black,
                        -fDistMLblSize.Width, -fDistScaled - fDistMLblSize.Height / 2);

                    e.Graphics.DrawString(fDistMLbl, this.Font, Brushes.Black,
                        -fDistMLblSize.Width, fDistScaled - fDistMLblSize.Height / 2);

                    float left = -e.ClipRectangle.Width / 2.0f;
                    float right = e.ClipRectangle.Width / 2.0f;
                    float top = -e.ClipRectangle.Height / 2.0f;
                    float bottom = e.ClipRectangle.Height / 2.0f;

                    e.Graphics.DrawLine(gridPen, left, 0.0f, right, 0.0f);
                    e.Graphics.DrawLine(gridPen, 0.0f, top, 0.0f, bottom);                 

                    
                    PointF[] pointsToDraw = new PointF[items.Length];
                    for (int i = 0; i < items.Length; i++)
                    {
                        float x = (float)(items[i].Longitude - meanLon) * scale;
                        float y = (float)(items[i].Latitude - meanLat) * scale;

                        pointsToDraw[i] = new PointF(x, y);
                    }
                    e.Graphics.DrawLines(pointPen, pointsToDraw);

                    var latLabel = StrUtils.AngleToString(meanLat);
                    var latLabelSize = e.Graphics.MeasureString(latLabel, this.Font);
                    var lonLabel = StrUtils.AngleToString(meanLon);
                    var lonLabelSize = e.Graphics.MeasureString(lonLabel, this.Font);

                    e.Graphics.DrawString(latLabel, this.Font, Brushes.Black, right - lonLabelSize.Width, 2.0f);
                    e.Graphics.DrawString(lonLabel, this.Font, Brushes.Black, 5.0f, top + 2.0f);
                }
            }           
        }

        private void GeoPlot_Resize(object sender, EventArgs e)
        {
            Invalidate();
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) JSC "SHTIL"
Russian Federation Russian Federation
underwater acoustics, communication and positioning.
Embedded software development. Digital signal processing.

Graduate of Volgograd Technical State University (2007),
Postgraduate student in Kovrov Technological State Academy (2012).

Comments and Discussions