Click here to Skip to main content
15,896,348 members
Articles / Programming Languages / C#

A C# Track Editor

Rate me:
Please Sign up or sign in to vote.
4.82/5 (18 votes)
2 Nov 2008CPOL2 min read 71.2K   6K   99  
This application is designed to put way points on a track map picture and to set the height of the track points in order to produce a TXT or XML file which resumes the track information.
/*****************************************************************************/
/* Project  : Track Editor                                                   */
/* File     : Track_Designer_Image_Control.cs                                */
/* Version  : 1                                                              */
/* Language : C#                                                             */
/* Summary  : A control which display a picture and includes features        */
/*            about drawing a track path                                     */
/* Creation : 12/11/2007                                                     */
/* Autor    : Guillaume CHOUTEAU                                             */
/* History  :                                                                */
/*****************************************************************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Track_Editor
{
    class TrackMapEditor_Control : Control
    {
        /*****************************************
        *                Fields                  *
        ******************************************/
        #region Fields

        // Track PATH
        List<Point> Track_Path = new List<Point>();

        // Scale Line
        List<Point> Scale_Line = new List<Point>();
        double Track_Picture_Scale_Px = 0;

        // Current point of the mouse pointer
        Point Current_Point = new Point();
        int Merge_Distance = 10; //px

        // Track_Picture
        int Width_Track_Picture = 200;
        int Height_Track_Picture = 100;
        Image Track_Picture = Resource_TrackEd.BackGround_Image;

        // Track Display
        int X_Track = 0;
        int Y_Track = 0;
        double Width_Rate = 0;
        double Height_Rate = 0;
        double Zoom_Rate = 1;

        // Pen brush
        SolidBrush Brush_Background = new SolidBrush(Color.Gray);
        Pen Pen_Bordure = new Pen(Color.Black, 4);
        Pen Pen_Current_Line = new Pen(Color.Black,4);
        Pen Pen_Scale = new Pen(Color.Yellow,4);

        // Icons
        Icon Start_Icon = Resource_TrackEd.StartFlag_Icon;
        Icon Point_Icon = Resource_TrackEd.PointFlag_Icon;

        // Flags
        Boolean Is_Edit_Scale = false;
        Boolean Is_Edit_Track = false;
        Boolean Is_Scale_Define = false;
        Boolean Is_Track_Define = false;
        Boolean Is_Near_Start_Point = false;

        // Events
        public event EventHandler Scale_Defined;
        public event EventHandler Track_Path_Defined;
        public event EventHandler TrackView_Rate_Changed;

        // Move track picture
        Point MovePicturePreviousPoint = new Point(0, 0);
        Boolean isMovePicturePreviousPointDefined = false;

        // Debug
        String Debug_String = "Aie!";
        double Distance_Start_To_Current = 0;
        Font Debug_Font = new Font("Arial", 10);
        SolidBrush Debug_Brush = new SolidBrush(Color.Black);

        #endregion

        /*****************************************
        *              Constructor               *
        ******************************************/
        #region Constructor

        public TrackMapEditor_Control()
        {
            // Double bufferisation
            SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint |
                      ControlStyles.AllPaintingInWmPaint, true);
        }

        #endregion

        /*****************************************
        *                 Paint                  *
        ******************************************/
        #region Paint

        protected override void OnPaint(PaintEventArgs pe)
        {
            // Calling the base class OnPaint
            base.OnPaint(pe);

            // Backgroung
            pe.Graphics.FillRectangle(Brush_Background, 0, 0, this.Size.Width, this.Size.Height);

            //!!! Track Display !!!
            Width_Track_Picture = Track_Picture.Width;
            Height_Track_Picture = Track_Picture.Height;
            Compute_Track_Position();
            pe.Graphics.DrawImage(Track_Picture, X_Track, Y_Track, (int)(Zoom_Rate * Width_Track_Picture), (int)(Zoom_Rate * Height_Track_Picture));

            //=== SCALE MODE ==================================================
            if (Is_Edit_Scale == true)
            {
                // Current scale line display
                if (Scale_Line.Count != 0)
                {
                    pe.Graphics.DrawLine(Pen_Scale, Current_Point, From_Track_Picture_To_Image_Viewer(Scale_Line[0]));
                }
            }
            //=== TRACK MODE ==================================================
            else if (Is_Edit_Track == true)
            {
                // Define the color of current track path line excpet for the first one 
                if (Track_Path.Count > 1)
                {
                    // Compute the distance between the first point of the track path and the current point
                    Distance_Start_To_Current = Compute_Distance(Current_Point, From_Track_Picture_To_Image_Viewer(Track_Path[0]));
                    
                    if (Distance_Start_To_Current < Merge_Distance)
                    {
                        // The points are near, the color line is set to red
                        Is_Near_Start_Point = true;
                        Pen_Current_Line.Color = Color.Red;
                        Debug_String = "_";
                    }
                    else
                    {
                        // Nothing special
                        Is_Near_Start_Point = false;
                        Pen_Current_Line.Color = Color.Black;
                        Debug_String = "_";
                    }
                }

                //!!! Current line display !!!
                if (Track_Path.Count != 0)
                {
                    // Current track path line
                    pe.Graphics.DrawLine(Pen_Current_Line, From_Track_Picture_To_Image_Viewer(Track_Path[Track_Path.Count - 1]), Current_Point);
                    // Debug info string
                    pe.Graphics.DrawString(Debug_String, Debug_Font, Debug_Brush, Current_Point);
                }
            }

            //=== CLASSIC DISPLAY =============================================

            //!!! Track path display !!!
            if (Track_Path.Count != 0)
            {
                // Start point
                if (Track_Path.Count != 0)
                {
                    pe.Graphics.DrawIcon(Start_Icon, From_Track_Picture_To_Image_Viewer(Track_Path[0]).X, From_Track_Picture_To_Image_Viewer(Track_Path[0]).Y - 32);
                }

                // Path points exept first one
                for (int i = 0; i < Track_Path.Count - 1; i++)
                {
                    // Path line
                    pe.Graphics.DrawLine(Pen_Bordure, From_Track_Picture_To_Image_Viewer(Track_Path[i]), From_Track_Picture_To_Image_Viewer(Track_Path[i + 1]));
                    // Path point icon flag
                    pe.Graphics.DrawIcon(Point_Icon, From_Track_Picture_To_Image_Viewer(Track_Path[i + 1]).X, From_Track_Picture_To_Image_Viewer(Track_Path[i + 1]).Y-32);
                }
            }

            //!!! Scale display !!!
            if (Is_Scale_Define == true)
            {
                pe.Graphics.DrawLine(Pen_Scale, From_Track_Picture_To_Image_Viewer(Scale_Line[0]), From_Track_Picture_To_Image_Viewer(Scale_Line[1]));
            }
        }

        #endregion

        /*****************************************
        *               CallBacks                *
        ******************************************/
        #region CallBacks

        protected override void OnMouseClick(MouseEventArgs e)
        {
            // Base event
            base.OnMouseClick(e);

            // Left button Click => Track or Scale
            if (e.Button == MouseButtons.Left)
            {
                // Mouse postion when button clicked
                Point NewPoint = new Point(e.X, e.Y);

                //=== SCALE MODE ====================================
                if (Is_Edit_Scale)
                {
                    // Convert point to track picture coordinate system and add to the scale line
                    NewPoint = From_Image_Viewer_To_Track_Picture(NewPoint);
                    Scale_Line.Add(NewPoint);

                    // Scale defined by the 2 points
                    if (Scale_Line.Count == 2)
                    {
                        // Compute distance in pixel between the two points of the scale line
                        Track_Picture_Scale_Px = Compute_Distance(Scale_Line[0], Scale_Line[1]);

                        // Launch the event and update flags
                        Launch_On_Scale_Defined();
                        Is_Edit_Scale = false;
                        Is_Scale_Define = true;
                    }       
                }
                else
                {
                    //=== TRACK MODE ================================
                    if (Is_Edit_Track == true)
                    {
                        // For the non first point track path
                        if (Track_Path.Count > 1)
                        {
                            // The points are near 
                            if (Is_Near_Start_Point == true)
                            {
                                // The current point is equal to the first
                                NewPoint.X = Track_Path[0].X;
                                NewPoint.Y = Track_Path[0].Y;
                                Track_Path.Add(NewPoint);

                                // The track path is completly defined
                                Launch_On_Track_Path_Defined();
                                Is_Edit_Track = false;
                                Is_Track_Define = true;
                            }
                        }

                        // The track path is not yet full defined
                        if (Is_Track_Define == false)
                        {
                            // A new point is added
                            NewPoint = From_Image_Viewer_To_Track_Picture(NewPoint);
                            Track_Path.Add(NewPoint);
                        }
                    }
                }

                // Refresh the control
                this.Refresh();
            }

            // Right button => remove point
            if (e.Button == MouseButtons.Right)
            {
                if (Track_Path.Count > 1)
                {
                    // Remove the last point of the track path
                    Track_Path.RemoveAt(Track_Path.Count - 1);
                    // Refresh the control
                    this.Refresh();
                }
            }

            // Middle buttton => Move and zoom picture init
            if (e.Button == MouseButtons.Middle)
            {
                this.Select();
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            // Base event
            base.OnMouseMove(e);

            // Position of the mouse cursor
            Current_Point.X = e.X;
            Current_Point.Y = e.Y;

            // Middle buttton => Move picture init
            if (e.Button == MouseButtons.Middle)
            {
                // Set the cursor icon
                this.Cursor = Cursors.NoMove2D;

                if (isMovePicturePreviousPointDefined == false)
                {
                    // No prevous point defined, the current point is the previous point
                    MovePicturePreviousPoint.X = e.X;
                    MovePicturePreviousPoint.Y = e.Y;
                    isMovePicturePreviousPointDefined = true;
                }

                // Compute rate distance between current point and previous point
                double DeltaRateX = (double)(MovePicturePreviousPoint.X - Current_Point.X) / this.Width;
                double DeltaRateY = (double)(MovePicturePreviousPoint.Y - Current_Point.Y) / this.Height;

                // Redefine the previous point
                MovePicturePreviousPoint.X = e.X;
                MovePicturePreviousPoint.Y = e.Y;

                // Set the new width rate for the x postion off the track picture
                Width_Rate = Width_Rate + DeltaRateX;

                // Check the rate is in his range 
                if (Width_Rate > 1)
                {
                    Width_Rate = 1;
                }
                else if (Width_Rate < 0)
                {
                    Width_Rate = 0;
                }

                // Set the new height rate for the y postion off the track picture
                Height_Rate = Height_Rate + DeltaRateY;

                // Check the rate is in his range 
                if (Height_Rate > 1)
                {
                    Height_Rate = 1;
                }
                else if (Height_Rate < 0)
                {
                    Height_Rate = 0;
                }

                // launch the event to inform that rates has changed
                Launch_On_TrackView_Rate_Changed();
            }

            // Refresh the control
            this.Refresh();
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            // Base event
            base.OnMouseWheel(e);

            // Zoom +
            if (e.Delta > 0)
            {
                Zoom_Rate += 0.1;
            }

            // Zoom -
            if (e.Delta < 0)
            {
                Zoom_Rate -= 0.1;
            }

            // Refresh the control
            this.Refresh();
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            // Set the cursor icon
            this.Cursor = Cursors.Default;

            // Reset the flag to define a new start previous point on the next middle button click
            isMovePicturePreviousPointDefined = false;
        }

        #endregion

        /*****************************************
        *                 Methods                *
        ******************************************/
        #region Methods

        /// <summary>
        /// Define the new track picture to draw on the control with the initial zoom ratio
        /// </summary>
        /// <param name="track_picture">The track picure display on the control</param>
        /// <param name="zoomRatio">The initial zoom ratio for the display</param>
        public void Set_Track_Picture(Image track_picture,double zoomRatio)
        {
            Track_Picture = track_picture;
            Zoom_Rate = zoomRatio;
            this.Refresh();
        }

        /// <summary>
        /// Return the rate postion of the track picture
        /// The rate is expressed between 0 and 1 and postion of the upper-left corner of
        /// the track picture is defined by X = control.width*widthRate Y = control.height*heightRate
        /// </summary>
        /// <return> An array with the rate informations [Width_Rate,Height_Rate]</return>
        public double[] GetTrackViewRate()
        {
            double[] RetCoeff = new double[2];

            RetCoeff[0] = Width_Rate;
            RetCoeff[1] = Height_Rate;

            return RetCoeff;
        }

        /// <summary>
        /// Compute the postion of the track picture in the control with the current rates and sizes
        /// </summary>
        private void Compute_Track_Position()
        {
            X_Track = (int)(-0.5 * (Zoom_Rate * Width_Track_Picture - this.Width) + 2 * (-Width_Rate + 0.5) * Zoom_Rate * Width_Track_Picture);
            Y_Track = (int)(-0.5 * (Zoom_Rate * Height_Track_Picture - this.Height) + 2 * (-Height_Rate + 0.5) * Zoom_Rate * Height_Track_Picture);
        }

        /// <summary>
        /// Define the width rate and the height rate for the position of the track picture in the control
        /// The rate is expressed between 0 and 1 and postion of the upper-left corner of
        /// the track picture is defined by X = control.width*widthRate Y = control.height*heightRate
        /// </summary>
        /// <param name="width_rate">The width rate</param>
        /// <param name="height_rate">The height rate</param>
        public void Move_View_Window(double width_rate, double height_rate)
        {
            Width_Rate = width_rate;
            Height_Rate = height_rate;

            this.Refresh();
        }

        /// <summary>
        /// Convert a point expressed in the Image_Viewer coordinate system
        /// into a point expressed in the Track_Picture coordinate system.
        /// </summary>
        /// <param name="point_viewer">Point defined in the image viewer system</param>
        /// <return>Point expressed in the track picture system</return>
        private Point From_Image_Viewer_To_Track_Picture(Point point_viewer)
        {
            Point Return_Point = new Point();

            Return_Point.X = (int)((-X_Track + point_viewer.X) / Zoom_Rate);
            Return_Point.Y = (int)((-Y_Track + point_viewer.Y) / Zoom_Rate);

            return (Return_Point);
        }

        /// <summary>
        /// Convert a point expressed in the Track_Picture coordinate system
        /// into a point expressed in the Track_Map coordinate system.
        /// </summary>
        /// <param name="point_picture">Point defined in the track picture system</param>
        /// <return>Point expressed in the track map system</return>
        private Point From_Track_Picture_To_Track_Map(Point point_picture)
        {
            Point Return_Point = new Point();

            Return_Point.X = point_picture.X;
            Return_Point.Y = Track_Picture.Height - point_picture.Y;

            return (Return_Point);
        }

        /// <summary>
        /// Convert a point expressed in the Track_Picture coordinate system
        /// into a point expressed in the Image_Viewer coordinate system.
        /// </summary>
        /// <param name="point_picture">Point defined in the track picture system</param>
        /// <return>Point expressed in the image viewer system</return>
        private Point From_Track_Picture_To_Image_Viewer(Point point_picture)
        {
            Point Return_Point = new Point();

            Return_Point.X = (int)(point_picture.X * Zoom_Rate + X_Track);
            Return_Point.Y = (int)(point_picture.Y * Zoom_Rate + Y_Track);

            return (Return_Point);
        }

        /// <summary>
        /// Compute the distance between two points
        /// </summary>
        /// <param name="point_a">First point</param>
        /// <param name="point_b">Second point</param>
        /// <return>The distance between point A and Point B</return>
        private double Compute_Distance(Point point_a, Point point_b)
        {
            double Return_Distance;

            Return_Distance = Math.Sqrt((point_a.X - point_b.X) * (point_a.X - point_b.X) + (point_a.Y - point_b.Y) * (point_a.Y - point_b.Y));

            return (Return_Distance);
        }

        /// <summary>
        /// Set the mode of the control
        /// </summary>
        /// <param name="scale">True for scale mode</param>
        /// <param name="track">True for track mode</param>
        public void Set_Edit_Mode(Boolean scale, Boolean track)
        {
            Is_Edit_Scale = scale;
            Is_Edit_Track = track;

            if (Is_Edit_Scale == true)
            {
                // Scale mode
                if (Is_Scale_Define == true)
                {
                    Scale_Line.Clear();
                    Is_Scale_Define = false;
                    Refresh();
                }
            }

            if (Is_Edit_Track == true)
            {
                // Edit mode
                if (Is_Track_Define == true)
                {
                    Track_Path.Clear();
                    Is_Track_Define = false;
                    Refresh();
                }
            }
        }

        /// <summary>
        /// Return the length in pixel of the scale line
        /// </summary>
        /// <return>The length in pixel of the scale line</return>
        public double Get_Track_Scale_Picture_Px()
        {
            return (Track_Picture_Scale_Px);
        }

        /// <summary>
        /// Return the points of the track path expressed in the track map coordinate system
        /// </summary>
        /// <return>The points of the track path</return>
        public List<Point> Get_Track_Path()
        {
            List<Point> Track_Map_Path = new List<Point>();

            // Convert each points
            foreach (Point trackPoint in Track_Path)
            {
                Point TrackMapPoint = new Point(0, 0);
                TrackMapPoint = From_Track_Picture_To_Track_Map(trackPoint);
                Track_Map_Path.Add(TrackMapPoint);
            }

            return (Track_Map_Path);
        }

        #endregion

        /*****************************************
        *                 Events                 *
        ******************************************/
        #region Events

        // On scale defined - - - 

        protected virtual void On_Scale_Defined(object sender, EventArgs e)
        {
            if(Scale_Defined != null)
                Scale_Defined(sender,e);
        }

        public void Launch_On_Scale_Defined()
        {
            On_Scale_Defined(this,EventArgs.Empty);
        }

        // On track view rate changed - - -

        protected virtual void On_TrackView_Rate_Changed(object sender, EventArgs e)
        {
            if (TrackView_Rate_Changed != null)
                TrackView_Rate_Changed(sender, e);
        }

        public void Launch_On_TrackView_Rate_Changed()
        {
            On_TrackView_Rate_Changed(this, EventArgs.Empty);
        }

        // On track path defined - - -
        
        protected virtual void On_Track_Path_Defined(object sender, EventArgs e)
        {
            if (Track_Path_Defined != null)
                Track_Path_Defined(sender, e);
        }

        public void Launch_On_Track_Path_Defined()
        {
            On_Track_Path_Defined(this, EventArgs.Empty);
        }

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

Comments and Discussions