Click here to Skip to main content
15,879,095 members
Articles / Programming Languages / XML

Bernie’s Trackviewer

Rate me:
Please Sign up or sign in to vote.
4.84/5 (27 votes)
12 Jun 2016CPOL7 min read 61.4K   4.2K   70  
View and edit your GPS track records on a nice GUI with online maps and aerial views.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace GPX
{
    public partial class TrackControl : UserControl
    {
        #region Variables and Properties
        private GMap.NET.Internals.Core _Core;
        private DateTime _LastDrawTime;
        private bool _DrawPending;
        private Timer timer1;
        bool _UseOffset;
        private int _LeftOffset;
        private int _TopOffset;

        private TrackSegment _Segment;
        public TrackSegment TrackSegmentShown
        {
            get { return _Segment; }
            set
            {
                _Segment = value;
                CreateWaypointsList();
            }
        }

        private DrawCategory _XCategory;
        public DrawCategory XCategory
        {
            get { return _XCategory; }
            set { _XCategory = value; }
        }

        private DrawCategory _YCategory;
        public DrawCategory YCategory
        {
            get { return _YCategory; }
            set { _YCategory = value; }
        }

        private bool _UseEqualScale;
        public bool UseEqualScale
        {
            get { return _UseEqualScale; }
            set { _UseEqualScale = value; }
        }

        private float _Zoom;
        public float Zoom
        {
            get { return _Zoom; }
            set { _Zoom = value; }
        }

        private bool _DrawWaypoints;
        public bool DrawWaypoints
        {
            get { return _DrawWaypoints; }
            set { _DrawWaypoints = value; }
        }

        private WaypointsStyle _StyleForWaypoints;
        public WaypointsStyle StyleForWaypoints
        {
            get { return _StyleForWaypoints; }
            set { _StyleForWaypoints = value; }
        }

        private bool _ShowAllPointsOfSegment;
        public bool ShowAllPointsOfSegment
        {
            get { return _ShowAllPointsOfSegment; }
            set { _ShowAllPointsOfSegment = value; }
        }

        private int _IndexOfFirstPointShown;
        public int IndexOfFirstPointShown
        {
            get { return _IndexOfFirstPointShown; }
            set { _IndexOfFirstPointShown = value; }
        }

        private int _IndexOfLastPointShown;
        public int IndexOfLastPointShown
        {
            get { return _IndexOfLastPointShown; }
            set { _IndexOfLastPointShown = value; }
        }

        private bool _ShowMap;
        public bool ShowMap
        {
            get { return _ShowMap; }
            set { _ShowMap = value; }
        }

        private GMap.NET.MapType _MapType;
        public GMap.NET.MapType MapType
        {
            get { return _MapType; }
            set { _MapType = value; }
        }

        private Color _WayPointsColor = Color.BlanchedAlmond;
        public Color WayPointsColor
        {
            get { return _WayPointsColor; }
            set { _WayPointsColor = value; }
        }

        private Color _WayPointsHighlight = Color.Gold;
        public Color WayPointsHighlight
        {
            get { return _WayPointsHighlight; }
            set { _WayPointsHighlight = value; }
        }

        private Color _TrackColor = Color.Red;
        public Color TrackColor
        {
            get { return _TrackColor; }
            set { _TrackColor = value; }
        }

        private Color _TrackColorHighlight = Color.Goldenrod;
        public Color TrackColorHighlight
        {
            get { return _TrackColorHighlight; }
            set { _TrackColorHighlight = value; }
        }

        private float _TrackThickness = 3.0f;
        public float TrackThickness
        {
            get { return _TrackThickness; }
            set { _TrackThickness = value; }
        }

        private WayPointOnMap _SelectedWayPointOnMap;
        private List<WayPointOnMap> _SelectedWayPointsOnMap;

        private List<WayPointOnMap> _WayPointsOnMap;
        private int _LeftMargin = 40;
        private int _LowerMargin = 12;
        private int _TopMargin = 5;
        private Bitmap _Bitmap;

        private Point _SelectionStart;
        private Point _SelectionEnd;
        private bool _Selecting;

        private double _XMax;
        private double _YMax;
        private double _XMin;
        private double _YMin;
        private double _XFactor;
        private double _YFactor;

        #endregion Variables and Properties

        #region Events
        public delegate void WayPointSelectedEventHandler(object sender, WayPointSelectedEventArgs wpArgs);
        public event WayPointSelectedEventHandler WayPointSelected;
        #endregion Events

        private bool IsDesignMode
        {
            get
            {
                return System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime;
            }
        }

        private System.Resources.ResourceManager ResourceManager
        {
            get { return GPXAppResourceManager.ResourceManager; }
        }

        public TrackControl()
        {
            InitializeComponent();

            if (IsDesignMode)
                return;

            _Bitmap = null;
            _Zoom = 1;
            _XCategory = DrawCategory.LongitudeKm;
            _YCategory = DrawCategory.LatitudeKm;
            _UseEqualScale = false;
            _Selecting = false;
            _DrawWaypoints = false;
            _ShowAllPointsOfSegment = true;
            _IndexOfFirstPointShown = 1;
            _IndexOfLastPointShown = 100000;

            //For maps
            {
                timer1 = new Timer(this.components);
                timer1.Interval = 2500;
                timer1.Tick += new System.EventHandler(this.timer1_Tick);

                GMap.NET.CacheProviders.FilePureImageCache imageCache = new GMap.NET.CacheProviders.FilePureImageCache();
                string cacheLocation = Defaults.GMapsFileCacheLocation;
                imageCache.CacheLocation = cacheLocation;
                GMap.NET.Internals.Cache.Instance.ImageCache = imageCache;

                GMap.NET.GMaps.Instance.ImageProxy = new GMap.NET.WindowsForms.WindowsFormsImageProxy();
                GMap.NET.GMaps.Instance.UseGeocoderCache = true;
                GMap.NET.GMaps.Instance.UseMemoryCache = true;
                GMap.NET.GMaps.Instance.UsePlacemarkCache = true;

                _Core = GMap.NET.Internals.Core.Instance;
                _Core.MapType = GMap.NET.MapType.GoogleSatellite;
                _Core.Projection = new GMap.NET.Projections.MercatorProjection();

                _Core.OnNeedInvalidation += new GMap.NET.NeedInvalidation(Core_OnNeedInvalidation);
                _Core.StartSystem();
            }
        }

        private void CreateWaypointsList()
        {
            if (_Segment == null)
                _WayPointsOnMap = null;
            else
            {
                _WayPointsOnMap = new List<WayPointOnMap>();
                foreach (WayPoint wp in _Segment.WayPoints)
                {
                    _WayPointsOnMap.Add(new WayPointOnMap(wp));
                }
            }
        }

        public void Draw()
        {
            if ((_Segment == null) || (_Segment.WayPoints.Count == 0))
            {
                //GPX_TrackControl_Draw0=The TrackSegment to be drawn was either not set or is empty.
                throw new ApplicationException(ResourceManager.GetString("GPX_TrackControl_Draw0"));
            }

            if ((_WayPointsOnMap == null) || (_WayPointsOnMap.Count != _Segment.WayPoints.Count))
                CreateWaypointsList();

            //determine hidden vs. shown waypoints and their applicable values
            foreach (WayPointOnMap wpm in _WayPointsOnMap)
            {
                //if only a selection of points is to be shown, check the points if they are to be included
                if (!_ShowAllPointsOfSegment)
                {
                    if (wpm.WayPoint.Index < _IndexOfFirstPointShown)
                        wpm.IsHidden = true;
                    else if (wpm.WayPoint.Index > _IndexOfLastPointShown)
                        wpm.IsHidden = true;
                    else
                        wpm.IsHidden = false;
                }
                else
                    wpm.IsHidden = false;

                if (!wpm.IsHidden)
                {
                    //Selected value: latitude, longitude, elevation, time, what ever....
                    wpm.XValue = GetSelectedValueFromWaypoint(wpm.WayPoint, _XCategory);
                    wpm.YValue = GetSelectedValueFromWaypoint(wpm.WayPoint, _YCategory);
                }
            }
            //get maximum and minimum for x and y values each
            int index = (_ShowAllPointsOfSegment ? 1 : _IndexOfFirstPointShown);
            _XMax = _WayPointsOnMap[index - 1].XValue;
            _YMax = _WayPointsOnMap[index - 1].YValue;
            _XMin = _WayPointsOnMap[index - 1].XValue;
            _YMin = _WayPointsOnMap[index - 1].YValue;
            for (int i = 1; i < _WayPointsOnMap.Count; i++)
            {
                if (!_WayPointsOnMap[i].IsHidden)
                {
                    _XMax = (_XMax < _WayPointsOnMap[i].XValue) ? _WayPointsOnMap[i].XValue : _XMax;
                    _YMax = (_YMax < _WayPointsOnMap[i].YValue) ? _WayPointsOnMap[i].YValue : _YMax;
                    _XMin = (_XMin > _WayPointsOnMap[i].XValue) ? _WayPointsOnMap[i].XValue : _XMin;
                    _YMin = (_YMin > _WayPointsOnMap[i].YValue) ? _WayPointsOnMap[i].YValue : _YMin;
                }
            }
            //get the size of control for drawing, reserve space for axes
            pnlImage.Width = Convert.ToInt32(this.ClientSize.Width * _Zoom);
            pnlImage.Height = Convert.ToInt32(this.ClientSize.Height * _Zoom);
            int drawWidth = pnlImage.Width - _LeftMargin - _TopMargin;
            int drawHeight = pnlImage.Height - _LowerMargin - _TopMargin;

            //now differentiate between external maps and internal graphs
            if (_ShowMap)
            {
                _UseOffset = true;
                _Core.BeginUpdate();

                //center: that's the center point for the _Core object
                GMap.NET.PointLatLng center = new GMap.NET.PointLatLng((_YMax + _YMin) / 2,
                     (_XMax + _XMin) / 2);
                _Core.CurrentPosition = center;
                _Core.MapType = _MapType;

                //top left and bootom right: for calculating zoom
                GMap.NET.PointLatLng topLeft = new GMap.NET.PointLatLng(_YMax, _XMin);
                GMap.NET.PointLatLng bottomRight = new GMap.NET.PointLatLng(_YMin, _XMax);

                //number of tiles fitting into the image
                int tilesX = drawWidth / _Core.Projection.TileSize.Width;
                int tilesY = drawHeight / _Core.Projection.TileSize.Height;

                //calculating zoom: when more tiles are required in one direction than fitting into the image
                //the zoom has been exceeded by 1.
                for (int zoomTmp = 0; zoomTmp <= 25; zoomTmp++)
                {
                    GMap.NET.Point pixelTopLeft = _Core.Projection.FromLatLngToPixel(topLeft, zoomTmp);
                    GMap.NET.Point tileTopLeft = _Core.Projection.FromPixelToTileXY(pixelTopLeft);
                    GMap.NET.Point pixelBottomRight = _Core.Projection.FromLatLngToPixel(bottomRight, zoomTmp);
                    GMap.NET.Point tileBottomRight = _Core.Projection.FromPixelToTileXY(pixelBottomRight);

                    if ((tileBottomRight.X - tileTopLeft.X > tilesX)
                        || (tileBottomRight.Y - tileTopLeft.Y > tilesY))
                    {
                        _Core.Zoom = zoomTmp - 1;
                        break;
                    }
                }
                //set size
                _Core.OnMapSizeChanged(drawWidth - _Core.Projection.TileSize.Width,
                    drawHeight - _Core.Projection.TileSize.Height);
                //get the MAP images
                _Core.EndUpdate();
            }
            else
            {
                _UseOffset = false;
                DetermineOffset(); //sets offset values to 0

                //scale for internal representation
                _XFactor = (_XMax - _XMin) / drawWidth;
                _YFactor = (_YMax - _YMin) / drawHeight;
                if (_UseEqualScale)
                {
                    _XFactor = (_XFactor > _YFactor) ? _XFactor : _YFactor;
                    _YFactor = _XFactor;
                }
            }

            //calculate position for each point
            foreach (WayPointOnMap wpm in _WayPointsOnMap)
            {
                if (!wpm.IsHidden)
                {
                    if (_ShowMap)
                    {
                        System.Drawing.Point present =
                            _Core.FromLatLngToLocal(new GMap.NET.PointLatLng((double)wpm.YValue, (double)wpm.XValue)).ToDrawingPoint();
                        wpm.XPixels = _LeftMargin + present.X;
                        wpm.YPixels = _TopMargin + present.Y;
                    }
                    else
                    {
                        wpm.XPixels = _LeftMargin + Convert.ToInt32((wpm.XValue - _XMin) / _XFactor);
                        wpm.YPixels = _TopMargin + Convert.ToInt32((_YMax - wpm.YValue) / _YFactor);
                    }
                }
                else
                {
                    wpm.XPixels = -1;
                    wpm.YPixels = -1;
                }
            }

            //and now draw it!
            _Bitmap = new Bitmap(pnlImage.Width, pnlImage.Height);
            if (_ShowMap)
                DrawGridForMap();
            else
                DrawGrid();

            DrawTrack();
        }

        private void DrawTrack()
        {
            Graphics graphics = Graphics.FromImage(_Bitmap);
            Point previous = new Point();
            Point nullPoint = new Point();
            foreach (WayPointOnMap wpm in _WayPointsOnMap)
            {
                if (wpm.IsHidden)
                {
                    previous = nullPoint;
                }
                else
                {
                    Point p1;
                    if (previous != nullPoint)
                        p1 = previous;
                    else
                    {
                        p1 = new Point(wpm.XPixels, wpm.YPixels);
                        p1.Offset(-_LeftOffset, -_TopOffset);
                    }
                    Point p2 = new Point(wpm.XPixels, wpm.YPixels);
                    p2.Offset(-_LeftOffset, -_TopOffset);

                    DrawWaypoint(graphics, p2, p1, wpm.IsHighlighted);

                    previous = p2;
                }
            }
            graphics.Dispose();

            _Bitmap.Save(Defaults.TrackControl_BitmapPath, System.Drawing.Imaging.ImageFormat.Bmp); //@"C:\temp\bitmap.bmp"
            this.Refresh();
        }

        private void DrawWaypoint(Graphics graphics, Point point, Point previousPoint, bool highLighted)
        {
            Pen pen;
            Pen penStandard = new Pen(_TrackColor, _TrackThickness);
            Pen penHighlight = new Pen(_TrackColorHighlight, _TrackThickness);
            Pen pointsPen;
            Pen pointsPenStandard = new Pen(_WayPointsColor, _TrackThickness);
            Pen pointsPenHighlight = new Pen(_WayPointsHighlight, _TrackThickness);
            pen = (highLighted) ? penHighlight : penStandard;
            graphics.DrawLine(pen, previousPoint, point);
            if (_DrawWaypoints)
            {
                pointsPen = (highLighted) ? pointsPenHighlight : pointsPenStandard;
                switch (_StyleForWaypoints)
                {
                    case WaypointsStyle.SmallPlus:
                        graphics.DrawLine(pointsPen, point.X - 2, point.Y, point.X + 2, point.Y);
                        graphics.DrawLine(pointsPen, point.X, point.Y - 2, point.X, point.Y + 2);
                        break;
                    case WaypointsStyle.BigPlus:
                        graphics.DrawLine(pointsPen, point.X - 4, point.Y, point.X + 4, point.Y);
                        graphics.DrawLine(pointsPen, point.X, point.Y - 4, point.X, point.Y + 4);
                        break;
                    case WaypointsStyle.SmallCircle:
                        graphics.DrawEllipse(pointsPen, point.X - 2, point.Y - 2, 4, 4);
                        break;
                    case WaypointsStyle.BigCircle:
                        graphics.DrawEllipse(pointsPen, point.X - 4, point.Y - 4, 8, 8);
                        break;
                    case WaypointsStyle.SmallX:
                        graphics.DrawLine(pointsPen, point.X - 2, point.Y - 2, point.X + 2, point.Y + 2);
                        graphics.DrawLine(pointsPen, point.X - 2, point.Y + 2, point.X + 2, point.Y - 2);
                        break;
                    case WaypointsStyle.BigX:
                        graphics.DrawLine(pointsPen, point.X - 4, point.Y - 4, point.X + 4, point.Y + 4);
                        graphics.DrawLine(pointsPen, point.X - 4, point.Y + 4, point.X + 4, point.Y - 4);
                        break;
                    case WaypointsStyle.SmallSquare:
                        graphics.DrawRectangle(pointsPen, point.X - 2, point.Y - 2, 4, 4);
                        break;
                    case WaypointsStyle.BigSquare:
                        graphics.DrawRectangle(pointsPen, point.X - 4, point.Y - 4, 8, 8);
                        break;
                }
            }
        }

        public List<WayPoint> GetSelection()
        {
            List<WayPoint> retVal = new List<WayPoint>();
            if (_SelectedWayPointsOnMap != null)
            {
                foreach (WayPointOnMap wpm in _SelectedWayPointsOnMap)
                    retVal.Add(wpm.WayPoint);
            }
            return retVal;
        }

        private void DrawGrid()
        {
            Pen penLine = new Pen(Color.Wheat);
            Brush brushValue = Brushes.White;
            Font font = new Font("Arial", 8.0f);
            Graphics g = Graphics.FromImage(_Bitmap);

            //Y Axis
            double pot = 0.0;
            double dY = (_YMax - _YMin) / 10;
            int decimals = 0;
            int log = Convert.ToInt32(Math.Floor(Math.Log10(dY)));
            if (log >= 0)
            {
                pot = Convert.ToInt32(Math.Pow(10, log));
                decimals = 0;
            }
            else
            {
                pot = 1.0 / Math.Pow(10, -log);
                decimals = -log;
            }
            dY = pot * Math.Round(dY / pot, 0);
            double yStart = 0.0;
            if (Math.Abs(_YMin) > 0.0001)
            {
                yStart = Convert.ToInt32(_YMin / dY) * dY;
            }
            while (yStart <= _YMax)
            {
                int yPos = _TopMargin + Convert.ToInt32((_YMax - yStart) / _YFactor);
                g.DrawLine(penLine, 0, yPos, _Bitmap.Width, yPos);
                string str = yStart.ToString("F" + decimals.ToString());
                g.DrawString(str, font, brushValue, 0.0f, (float)yPos);
                yStart = Math.Round(yStart + dY, decimals);
            }

            //x axis
            double dX = (_XMax - _XMin) / 10;
            log = Convert.ToInt32(Math.Floor(Math.Log10(dX)));
            if (log >= 0)
            {
                pot = Convert.ToInt32(Math.Pow(10, log));
                decimals = 0;
            }
            else
            {
                pot = 1.0 / Math.Pow(10, -log);
                decimals = -log;
            }
            dX = pot * Math.Round(dX / pot, 0);
            double xStart = 0.0;
            if (Math.Abs(_XMin) > 0.0001)
            {
                xStart = Convert.ToInt32(_XMin / dX) * dX;
            }
            while (xStart <= _XMax)
            {
                int xPos = _LeftMargin + Convert.ToInt32((xStart - _XMin) / _XFactor);
                g.DrawLine(penLine, xPos, 0, xPos, _Bitmap.Height);
                string str = xStart.ToString("F" + decimals.ToString());
                g.DrawString(str, font, brushValue, (float)xPos, (float)(_Bitmap.Height - _LowerMargin));
                xStart = Math.Round(xStart + dX, decimals);
            }

            penLine.Dispose();
            g.Dispose();
        }

        private void DrawGridForMap()
        {
            System.Drawing.Point topLeftReceived = new System.Drawing.Point();
            System.Drawing.Point bottomRightReceived = new System.Drawing.Point();

            if (_Core.tileDrawingList.GetExtension(ref topLeftReceived, ref bottomRightReceived))
            {
                topLeftReceived = new System.Drawing.Point(topLeftReceived.X * _Core.Projection.TileSize.Width, topLeftReceived.Y * _Core.Projection.TileSize.Height);
                bottomRightReceived = new System.Drawing.Point((bottomRightReceived.X + 1) * _Core.Projection.TileSize.Width, (bottomRightReceived.Y + 1) * _Core.Projection.TileSize.Height);
                int zoom = _Core.Zoom;

                GMap.NET.PointLatLng topLeft = _Core.Projection.FromPixelToLatLng(topLeftReceived.X, topLeftReceived.Y, zoom);
                GMap.NET.PointLatLng bottomRight = _Core.Projection.FromPixelToLatLng(bottomRightReceived.X, bottomRightReceived.Y, zoom);

                //center: das wird als Mittelpunkt �bergeben
                GMap.NET.PointLatLng center = new GMap.NET.PointLatLng((_YMax + _YMin) / 2,
                     (_XMax + _XMin) / 2);

                Pen penLine = new Pen(Color.Wheat);
                Brush brushValue = Brushes.White;
                Font font = new Font("Arial", 8.0f);
                Graphics g = Graphics.FromImage(_Bitmap);

                try
                {
                    //Y Axis
                    double pot = 0.0;
                    double dY = (topLeft.Lat - bottomRight.Lat) / 10;
                    int decimals = 0;
                    int log = Convert.ToInt32(Math.Floor(Math.Log10(dY)));
                    if (log >= 0)
                    {
                        pot = Convert.ToInt32(Math.Pow(10, log));
                        decimals = 0;
                    }
                    else
                    {
                        pot = 1.0 / Math.Pow(10, -log);
                        decimals = -log;
                    }
                    dY = pot * Math.Round(dY / pot, 0);
                    double yStart = 0.0;
                    if (Math.Abs(bottomRight.Lat) > 0.0001)
                    {
                        yStart = Convert.ToInt32(bottomRight.Lat / dY) * dY;
                    }
                    while (yStart <= topLeft.Lat)
                    {
                        GMap.NET.Point yPoint = _Core.Projection.FromLatLngToPixel(new GMap.NET.PointLatLng(yStart, center.Lng), zoom);
                        int yPos = yPoint.Y - topLeftReceived.Y - _TopOffset + _TopMargin;
                        //int yPos = Convert.ToInt32((topLeft.Lat - yStart) / _YFactor) - _TopOffset;
                        g.DrawLine(penLine, 0, yPos, _Bitmap.Width, yPos);
                        string str = yStart.ToString("F" + decimals.ToString());
                        g.DrawString(str, font, brushValue, 0.0f, (float)yPos);
                        yStart = Math.Round(yStart + dY, decimals);
                    }

                    //x axis
                    double dX = (bottomRight.Lng - topLeft.Lng) / 10;
                    log = Convert.ToInt32(Math.Floor(Math.Log10(dX)));
                    if (log >= 0)
                    {
                        pot = Convert.ToInt32(Math.Pow(10, log));
                        decimals = 0;
                    }
                    else
                    {
                        pot = 1.0 / Math.Pow(10, -log);
                        decimals = -log;
                    }
                    dX = pot * Math.Round(dX / pot, 0);
                    double xStart = 0.0;
                    if (Math.Abs(topLeft.Lng) > 0.0001)
                    {
                        xStart = Convert.ToInt32(topLeft.Lng / dX) * dX;
                    }
                    while (xStart <= bottomRight.Lng)
                    {
                        GMap.NET.Point xPoint = _Core.Projection.FromLatLngToPixel(new GMap.NET.PointLatLng(center.Lat, xStart), zoom);
                        int xPos = xPoint.X - topLeftReceived.X - _LeftOffset + _LeftMargin;
                        //int xPos = Convert.ToInt32((xStart - topLeft.Lng) / _XFactor) - _TopOffset;
                        g.DrawLine(penLine, xPos, 0, xPos, _Bitmap.Height);
                        string str = xStart.ToString("F" + decimals.ToString());
                        g.DrawString(str, font, brushValue, (float)xPos, (float)pnlImage.ClientSize.Height - 12);
                        xStart = Math.Round(xStart + dX, decimals);
                    }
                }
                catch
                {
                }
                finally
                {
                    penLine.Dispose();
                    g.Dispose();
                }
            }
        }

        private double GetSelectedValueFromWaypoint(WayPoint wp, DrawCategory drawCategory)
        {
            double retVal = 0;
            switch (drawCategory)
            {
                case DrawCategory.DistanceFromStart:
                    retVal = wp.GetDistanceFromStart().GetLength(wp.Latitude);
                    break;
                case DrawCategory.Elevation:
                    retVal = Convert.ToDouble(wp.Elevation);
                    break;
                case DrawCategory.Latitude:
                    retVal = Convert.ToDouble(wp.Latitude);
                    break;
                case DrawCategory.LatitudeKm:
                    retVal = wp.GetLatitudeKm();
                    break;
                case DrawCategory.Longitude:
                    retVal = Convert.ToDouble(wp.Longitude);
                    break;
                case DrawCategory.LongitudeKm:
                    retVal = wp.GetLongitudeKm();
                    break;
                case DrawCategory.Speed:
                    retVal = wp.GetSpeed();
                    break;
                case DrawCategory.SpeedvectorEast:
                    retVal = wp.GetSpeedVector().DeltaLongitude;
                    break;
                case DrawCategory.SpeedvectorElevation:
                    retVal = wp.GetSpeedVector().DeltaElevation;
                    break;
                case DrawCategory.SpeedvectorNorth:
                    retVal = wp.GetSpeedVector().DeltaLatitude;
                    break;
                case DrawCategory.Time:
                    retVal = wp.GetTimeSinceStartSeconds();
                    break;
                case DrawCategory.TrackDistanceFromStart:
                    retVal = wp.GetTrackDistanceFromStart();
                    break;
                case DrawCategory.DirectionEast:
                    retVal = wp.GetDirectionVector().DeltaLongitude;
                    break;
                case DrawCategory.DirectionNorth:
                    retVal = wp.GetDirectionVector().DeltaLatitude;
                    break;
                case DrawCategory.DirectionVertical:
                    retVal = wp.GetDirectionVector().DeltaElevation;
                    break;
                case DrawCategory.PercrentAscent:
                    retVal = wp.GetAscent();
                    break;
                default:
                    //GPX_TrackControl_GetSelectedValueFromWaypoint0=Unknown category for drawing
                    throw new ArgumentException(ResourceManager.GetString("GPX_TrackControl_GetSelectedValueFromWaypoint0"));
            }

            return retVal;
        }

        private void SetWaypointValueForCoordinates(WayPoint wp, int x, int y)
        {
            if (_ShowMap)
            {
                GMap.NET.PointLatLng pos = _Core.FromLocalToLatLng(x, y);
                wp.Latitude = Convert.ToDecimal(pos.Lat);
                wp.Longitude = Convert.ToDecimal(pos.Lng);
            }
            else
            {
                switch (_XCategory)
                {
                    case DrawCategory.Elevation:
                        wp.Elevation = Convert.ToDecimal(_XMin + _XFactor * x); //_XMin + _XFactor * (x - _LeftMargin)
                        break;
                    case DrawCategory.Latitude:
                        wp.Latitude = Convert.ToDecimal(_XMin + _XFactor * x);
                        break;
                    case DrawCategory.LatitudeKm:
                        double latitudeKm = _XMin + _XFactor * x;
                        wp.Latitude = Convert.ToDecimal(latitudeKm / GPXUtils.KmPerDegree);
                        break;
                    case DrawCategory.Longitude:
                        wp.Longitude = Convert.ToDecimal(_XMin + _XFactor * x);
                        break;
                    case DrawCategory.LongitudeKm:
                        double longitudeKm = _XMin + _XFactor * x;
                        wp.Longitude = Convert.ToDecimal(longitudeKm / GPXUtils.KmPerDegreeAtLatitude(wp.Latitude));
                        break;
                    default:
                        //GPX_TrackControl_SetWaypointValueForCoordinates0=X Category not valid for editing
                        throw new ArgumentException(ResourceManager.GetString("GPX_TrackControl_SetWaypointValueForCoordinates0"));
                }

                switch (_YCategory)
                {
                    case DrawCategory.Elevation:
                        wp.Elevation = Convert.ToDecimal(_YMax - _YFactor * y); //_YMax - _YFactor * (y - _GeneralMargin)
                        break;
                    case DrawCategory.Latitude:
                        wp.Latitude = Convert.ToDecimal(_YMax - _YFactor * y);
                        break;
                    case DrawCategory.LatitudeKm:
                        double latitudeKm = _YMax - _YFactor * y;
                        wp.Latitude = Convert.ToDecimal(latitudeKm / GPXUtils.KmPerDegree);
                        break;
                    case DrawCategory.Longitude:
                        wp.Longitude = Convert.ToDecimal(_YMax - _YFactor * y);
                        break;
                    case DrawCategory.LongitudeKm:
                        double longitudeKm = _YMax - _YFactor * y;
                        wp.Longitude = Convert.ToDecimal(longitudeKm / GPXUtils.KmPerDegreeAtLatitude(wp.Latitude));
                        break;
                    default:
                        //GPX_TrackControl_SetWaypointValueForCoordinates1=Y Category not valid for editing
                        throw new ArgumentException(ResourceManager.GetString("GPX_TrackControl_SetWaypointValueForCoordinates1"));
                }
            }
        }

        private void ResetHighlight()
        {
            //Utils.DebugStackTrace();
            if (_WayPointsOnMap != null)
            {
                foreach (WayPointOnMap wpm in _WayPointsOnMap)
                    wpm.IsHighlighted = false;
            }
        }

        private void pnlImage_Paint(object sender, PaintEventArgs e)
        {
            try
            {
                if (_Bitmap != null)
                {
                    e.Graphics.DrawImageUnscaled(_Bitmap, 0, 0);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("pnlImage_Paint: " + ex.ToString());
            }
        }

        private void pnlImage_MouseDown(object sender, MouseEventArgs e)
        {
            try
            {
                if (e != null)
                {
                    if (e.Button == MouseButtons.Left)
                    {
                        _Selecting = true;
                        _SelectionStart = e.Location;
                        _SelectedWayPointsOnMap = null;
                        ResetHighlight();
                    }
                    else if (e.Button == MouseButtons.Right)
                    {
                        _SelectedWayPointOnMap = GetWaypointFromPosition(e.X, e.Y);
                        ////init Drag&Drop
                        //if (_SelectedWayPointsOnMap != null)
                        //{
                        //    //DoDragDrop(new TrackControlDataObject("WayPointsOnMap", _SelectedWayPointsOnMap, this), DragDropEffects.Copy);
                        //    DoDragDrop(new TrackControlDataObject(DataFormats.FileDrop, null, this), DragDropEffects.Copy);
                        //}
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("pnlImage_MouseDown: " + ex.ToString());
            }
        }

        private void pnlImage_MouseMove(object sender, MouseEventArgs e)
        {
            try
            {
                if (e != null)
                {
                    if (_Selecting)
                    {
                        this.Refresh();
                        Graphics g = pnlImage.CreateGraphics();
                        Pen pen = new Pen(Color.Blue);
                        int top = Math.Min(_SelectionStart.Y, e.Y);
                        int left = Math.Min(_SelectionStart.X, e.X);
                        int width = Math.Max(_SelectionStart.X, e.X) - left;
                        int height = Math.Max(_SelectionStart.Y, e.Y) - top;
                        g.DrawRectangle(pen, new Rectangle(left, top, width, height));
                        g.Dispose();
                    }
                    else if (_SelectedWayPointOnMap != null)
                    {
                        if (_ShowMap)
                        {
                            _SelectedWayPointOnMap.XPixels = e.X + _LeftOffset;
                            _SelectedWayPointOnMap.YPixels = e.Y + _TopOffset;
                        }
                        else
                        {
                            _SelectedWayPointOnMap.XPixels = e.X;
                            _SelectedWayPointOnMap.YPixels = e.Y;
                        }
                        DrawTrack();
                    }
                    else
                    {
                        WayPointOnMap wpm = GetWaypointFromPosition(e.X, e.Y);
                        if (wpm == null)
                        {
                            if (_ShowMap)
                            {
                                //Tooltip shows position
                                GMap.NET.PointLatLng pos = _Core.FromLocalToLatLng(e.X + _LeftOffset - _LeftMargin, e.Y + _TopOffset - _TopMargin);
                                //GPX_TrackControl_pnlImage_MouseMove0=Position:\r\nLatitude \t= {0:F4}\r\nLongitude\t= {1:F4}
                                string msg = string.Format(ResourceManager.GetString("GPX_TrackControl_pnlImage_MouseMove0"), pos.Lat, pos.Lng);
                                toolTip1.SetToolTip(pnlImage, msg);
                            }
                            else
                            {
                                toolTip1.RemoveAll();
                            }
                        }
                        else
                        {
                            //System.Diagnostics.Debug.WriteLine(string.Format("Waypoint detetcted at {0},{1}: {2},{3}", e.X, e.Y, wpm.XPixels, wpm.YPixels));
                            StringBuilder toolTip = new StringBuilder();
                            string info = Defaults.TrackControl_WayPointInfo;
                            string[] lines = info.Split("|".ToCharArray());
                            foreach (string line in lines)
                            {
                                string[] vals = line.Split(",".ToCharArray());
                                string prop = vals[1];
                                string format = vals[2];
                                object retVal = null;
                                try
                                {
                                    PropertyInfo pi = wpm.WayPoint.GetType().GetProperty(prop);
                                    if (pi != null)
                                    {
                                        retVal = pi.GetValue(wpm.WayPoint, null);
                                    }
                                    else
                                    {
                                        MethodInfo mi = wpm.WayPoint.GetType().GetMethod(prop);
                                        retVal = mi.Invoke(wpm.WayPoint, null);
                                    }
                                    string dataLine = vals[0] + ":\t" + string.Format(format, retVal);
                                    toolTip.AppendLine(dataLine);
                                }
                                catch (Exception) { }
                            }
                            toolTip.Remove(toolTip.Length - 2, 2);
                            toolTip1.SetToolTip(pnlImage, toolTip.ToString());
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("pnlImage_MouseMove: " + ex.ToString());
            }
        }

        private void pnlImage_MouseUp(object sender, MouseEventArgs e)
        {
            try
            {
                if (e != null)
                {
                    if (_Selecting)
                    {
                        Point p1 = new Point(e.X < _SelectionStart.X ? e.X : _SelectionStart.X, e.Y < _SelectionStart.Y ? e.Y : _SelectionStart.Y);
                        _SelectionEnd = new Point(e.X > _SelectionStart.X ? e.X : _SelectionStart.X, e.Y > _SelectionStart.Y ? e.Y : _SelectionStart.Y);
                        _SelectionStart = p1;
                        _Selecting = false;
                        Graphics g = this.CreateGraphics();
                        Pen pen = new Pen(Color.Blue);
                        g.DrawRectangle(pen, new Rectangle(_SelectionStart.X, _SelectionStart.Y, _SelectionEnd.X - _SelectionStart.X, _SelectionEnd.Y - _SelectionStart.Y));
                        g.Dispose();
                        //calculate the selection
                        _SelectedWayPointsOnMap = new List<WayPointOnMap>();
                        foreach (WayPointOnMap wpm in _WayPointsOnMap)
                        {
                            if (wpm.IsInBounds(_SelectionStart.X, _SelectionStart.Y, _SelectionEnd.X, _SelectionEnd.Y))
                            {
                                wpm.IsHighlighted = true;
                                _SelectedWayPointsOnMap.Add(wpm);
                            }
                        }
                        Draw();
                    }
                    else if (_SelectedWayPointOnMap != null)
                    {
                        //calculate x and y values for the point
                        int x = e.X + _LeftOffset - _LeftMargin;
                        int y = e.Y + _TopOffset - _TopMargin;
                        SetWaypointValueForCoordinates(_SelectedWayPointOnMap.WayPoint, x, y);
                        _SelectedWayPointOnMap = null;
                        _Segment.Recalculate();
                        Draw();
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("pnlImage_MouseUp: " + ex.ToString());
            }
        }

        private void pnlImage_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            try
            {
                if (e != null)
                {
                    WayPointOnMap wpm = GetWaypointFromPosition(e.X, e.Y);
                    if (wpm != null)
                    {
                        if (WayPointSelected != null)
                            this.WayPointSelected(this, new WayPointSelectedEventArgs(wpm.WayPoint));
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("pnlImage_MouseClick: " + ex.ToString());
            }
        }

        private void pnlImage_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            try
            {
                //edit Waypoint
                if (e != null)
                {
                    WayPointOnMap wpm = GetWaypointFromPosition(e.X, e.Y);
                    if (wpm != null)
                    {
                        EditWaypointDialog ewd = new EditWaypointDialog();
                        ewd.WayPoint = wpm.WayPoint;
                        if (ewd.ShowDialog() == DialogResult.OK)
                        {
                            _Segment.Recalculate();
                            Draw();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                GPXAppUtils.handleException(ex);
            }
        }

        private WayPointOnMap GetWaypointFromPosition(int X, int Y)
        {
            WayPointOnMap wpm = null;
            int delta = 3;
            foreach (WayPointOnMap wp in _WayPointsOnMap)
            {
                if (wp.IsInBounds(X + _LeftOffset - delta, Y + _TopOffset - delta, X + _LeftOffset + delta, Y + _TopOffset + delta))
                {
                    wpm = wp;
                    break;
                }
            }
            return wpm;
        }

        #region DragDrop

        private class TrackControlDataObject : DataObject
        {
            private Control _Source;
            public Control Source
            {
                get { return _Source; }
                set { _Source = value; }
            }

            public TrackControlDataObject(string format, object data, Control source)
                : base(format, data)
            {
                _Source = source;
            }
        }
        #endregion DragDrop

        #region Drawing of Maps
        private void Core_OnNeedInvalidation()
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new MethodInvoker(Core_OnNeedInvalidation));
                return;
            }

            System.Diagnostics.Debug.WriteLine(string.Format("{0} TrackControl._Core_OnNeedInvalidation", DateTime.Now));
            if (DateTime.Now - _LastDrawTime < new TimeSpan((long)2e+7))
            {
                _DrawPending = true;
                return;
            }

            timer1.Stop();
            DrawImage();
            timer1.Start();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (_DrawPending)
                DrawImage();
        }

        private void DrawImage()
        {
            if (_Bitmap == null || !_ShowMap)
                return;

            if (this.InvokeRequired)
            {
                this.Invoke(new MethodInvoker(DrawImage));
                return;
            }

            _DrawPending = false;
            System.Drawing.Point topLeft = new System.Drawing.Point();
            System.Drawing.Point bottomRight = new System.Drawing.Point();
            if (_Core.tileDrawingList.GetExtension(ref topLeft, ref bottomRight))
            {
                _LastDrawTime = DateTime.Now;
                System.Diagnostics.Debug.WriteLine(string.Format("{0} TrackControl.DrawImage: TopLeft={1}, BottomRight={2}", DateTime.Now, topLeft, bottomRight));
                Graphics graphics = Graphics.FromImage(_Bitmap);
                DetermineOffset();

                for (int x = topLeft.X; x <= bottomRight.X; x++)
                {
                    for (int y = topLeft.Y; y <= bottomRight.Y; y++)
                    {
                        int xOffset = (x - topLeft.X) * _Core.Projection.TileSize.Width - _LeftOffset + _LeftMargin;
                        int yOffset = (y - topLeft.Y) * _Core.Projection.TileSize.Height - _TopOffset + _TopMargin;
                        System.Drawing.Point location = new System.Drawing.Point(xOffset, yOffset);

                        GMap.NET.Internals.Tile tile = _Core.Matrix[new GMap.NET.Point(x, y)];
                        if (tile != null)
                        {
                            foreach (GMap.NET.PureImage img in tile.Overlays)
                            {
                                if (img is GMap.NET.WindowsForms.WindowsFormsImage)
                                {
                                    System.IO.MemoryStream ms = img.Data;
                                    Image image = (img as GMap.NET.WindowsForms.WindowsFormsImage).Img;
                                    if (image != null)
                                    {
                                        graphics.DrawImage(image, location);
                                    }
                                }
                            }
                        }
                        else
                        {
                            //draw empty image
                            Brush brush = Brushes.Bisque;
                            graphics.FillRectangle(brush, xOffset, yOffset, _Core.Projection.TileSize.Width, _Core.Projection.TileSize.Height);
                        }
                    }
                }

                DrawGridForMap();
                DrawTrack();

                graphics.Dispose();
                GC.WaitForPendingFinalizers();
                GC.Collect(1, GCCollectionMode.Optimized);
                _LastDrawTime = DateTime.Now;

                //sometimes not all tiles are downloaded!
                if (_Core.tileLoadQueue.Count > 0)
                {
                    System.Diagnostics.Debug.WriteLine(string.Format("{0} TrackControl.DrawImage - Restarting Tile Load", DateTime.Now));
                    _Core.StartProcessLoadTasks();
                }
            }
        }
        private void DetermineOffset()
        {
            if (_UseOffset)
            {
                System.Drawing.Point topLeftReceived = new System.Drawing.Point();
                System.Drawing.Point bottomRightReceived = new System.Drawing.Point();

                if (_Core.tileDrawingList.GetExtension(ref topLeftReceived, ref bottomRightReceived))
                {
                    topLeftReceived = new System.Drawing.Point(topLeftReceived.X * _Core.Projection.TileSize.Width, topLeftReceived.Y * _Core.Projection.TileSize.Height);
                    int zoom = _Core.Zoom;
                    GMap.NET.PointLatLng topLeft = new GMap.NET.PointLatLng(_YMax, _XMin);
                    GMap.NET.PointLatLng bottomRight = new GMap.NET.PointLatLng(_YMin, _XMax);
                    //wo liegen der unterste und der rechteste Punkt
                    GMap.NET.Point bottomRightPixel = _Core.Projection.FromLatLngToPixel(bottomRight, zoom);
                    if (bottomRightPixel.X - topLeftReceived.X > pnlImage.ClientSize.Width)
                    {
                        _LeftOffset = bottomRightPixel.X - topLeftReceived.X - pnlImage.ClientSize.Width + 5;
                    }
                    else
                    {
                        _LeftOffset = 0;
                    }
                    if (bottomRightPixel.Y - topLeftReceived.Y > pnlImage.ClientSize.Height)
                    {
                        _TopOffset = bottomRightPixel.Y - topLeftReceived.Y - pnlImage.ClientSize.Height + 5;
                    }
                    else
                    {
                        _TopOffset = 0;
                    }
                }
                else
                {
                    _LeftOffset = 0;
                    _TopOffset = 0;
                }
            }
            else
            {
                _LeftOffset = 0;
                _TopOffset = 0;
            }
        }
        #endregion Drawing of Maps
    }
}

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)
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions