ScheduleCanvas.cs 7.21 KB
using RoboforkApp.DataModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace RoboforkApp
{
    public class ScheduleCanvas : Canvas
    {
        private double COOR_Y = 65;
        const double RADIUS_NODE = 25;
        public simulationRobo simulation;
        private VehicleModelList vehicleModelList;
        private Point _startPoint;
        private Point _endPoint;
        private bool _isGoal = false;
        private double _speed;
        private int _index;

        private List<ucNode> _lstNode;

        /// <summary>
        /// Create simulation
        /// </summary>
        /// <param name="lstNode">List node on schedule</param>
        /// <param name="vehicleModel">Vehicle model on map</param>
        /// <param name="vehicleIndex">Current index of vehicle</param>
        public void CreateSimulation(List<ucNode> lstNode, VehicleModel vehicleModel, int vehicleIndex)
        {
            //If node is less than 2 so return
            if (this.Children.Count < 2)
            {
                return;
            }

            this.Children.Remove(simulation);
            this.COOR_Y = DesignerCanvas.CanvasScheduleHeight / 2 - 15;

            //Init data
            this._lstNode = lstNode;
            this.vehicleModelList = vehicleModel.VehicleModelList[vehicleIndex];
            this._startPoint = new Point(Canvas.GetLeft(_lstNode[_index]) + RADIUS_NODE, COOR_Y);
            this._endPoint = new Point(Canvas.GetLeft(_lstNode[_index + 1]) + RADIUS_NODE, COOR_Y);

            //Get speed
            double scheDis = GetDistance(_startPoint, _endPoint);
            double mapDis = GetDistance(new Point(vehicleModelList.pointMapList[_index].pointMap_X, vehicleModelList.pointMapList[_index].pointMap_Y),
                                        new Point(vehicleModelList.pointMapList[_index + 1].pointMap_X, vehicleModelList.pointMapList[_index + 1].pointMap_Y + 1));
            this._speed = GetSpeed(mapDis, scheDis, vehicleModelList.pointMapList[_index].speed_Map);

            //Check next node is goal
            this._index += 1;
            if (_index == _lstNode.Count - 1)
            {
                _isGoal = true;
            }

            // Start simulation
            RoboSimulation();
        }

        /// <summary>
        /// Create robo simulation on line
        /// </summary>
        private void RoboSimulation()
        {
            simulation = new simulationRobo();
            simulation.storyBoard = CreatPathAnimation(_startPoint, _endPoint, _speed);
            this.Children.Add(simulation);
        }

        /// <summary>
        /// Get storyboard
        /// </summary>
        /// <param name="startPoint">Point start line</param>
        /// <param name="endPoit">Point end line</param>
        /// <param name="speed">speed on line</param>
        /// <returns>Storyboard</returns>
        private Storyboard CreatPathAnimation(Point startPoint, Point endPoit, double speed)
        {
            PathGeometry animationPath = new PathGeometry();
            PathFigure pFigure = new PathFigure();
            pFigure.StartPoint = startPoint; //new Point(50, 65);
            LineSegment lineSegment = new LineSegment();
            lineSegment.Point = endPoit; // new Point(800, 65);
            pFigure.Segments.Add(lineSegment);
            animationPath.Figures.Add(pFigure);

            // Freeze the PathGeometry for performance benefits.
            animationPath.Freeze();

            // Create a MatrixAnimationUsingPath to move the
            // simulation along the path by animating
            // its MatrixTransform.
            MatrixAnimationUsingPath matrixAnimation = new MatrixAnimationUsingPath();
            matrixAnimation.PathGeometry = animationPath;
            matrixAnimation.SpeedRatio = speed;
            matrixAnimation.AutoReverse = false;
            matrixAnimation.DoesRotateWithTangent = true;
            matrixAnimation.Completed += delegate { AnimationCompleted(this._isGoal); };

            // Set the animation to target the Matrix property
            // of the MatrixTransform named "ButtonMatrixTransform".
            Storyboard.SetTargetName(matrixAnimation, "fl");
            Storyboard.SetTargetProperty(matrixAnimation, new PropertyPath(MatrixTransform.MatrixProperty));

            // Create a Storyboard to contain and apply the animation.
            Storyboard pathAnimationStoryboard = new Storyboard();
            pathAnimationStoryboard.Children.Add(matrixAnimation);

            return pathAnimationStoryboard;
        }

        /// <summary>
        /// Process when simulation is end line
        /// </summary>
        /// <param name="isGoal">check is node end</param>
        private void AnimationCompleted(bool isGoal)
        {
            // If not end node
            if (!isGoal)
            {
                this.Children.Remove(simulation);
                this._startPoint = _endPoint;
                this._endPoint = new Point(Canvas.GetLeft(_lstNode[_index + 1]) + RADIUS_NODE, COOR_Y);

                //Get speed
                double scheDis = GetDistance(_startPoint, _endPoint);
                double mapDis = GetDistance(new Point(vehicleModelList.pointMapList[_index].pointMap_X, vehicleModelList.pointMapList[_index].pointMap_Y),
                                            new Point(vehicleModelList.pointMapList[_index + 1].pointMap_X, vehicleModelList.pointMapList[_index + 1].pointMap_Y + 1));
                this._speed = GetSpeed(mapDis, scheDis, vehicleModelList.pointMapList[_index].speed_Map);

                //Check next node is goal
                this._index += 1;
                if (this._index == this._lstNode.Count - 1)
                {
                    this._isGoal = true;
                }
                RoboSimulation();
                return;
            }

            // Reset data when finish
            this._index = 0;
            this._speed = 0;
            this._isGoal = false;
        }

        /// <summary>
        /// Get speed on schedule
        /// </summary>
        /// <param name="mapDis">Distance the line on Map</param>
        /// <param name="scheDis">Distance the line on Schedule</param>
        /// <param name="mapSpeed">Speed the fork on Map</param>
        /// <returns>Speed the fork on schedule</returns>
        private double GetSpeed(double mapDis, double scheDis, double mapSpeed)
        {
            if (mapDis == 0)
                return 0.0;

            return mapSpeed * (scheDis / mapDis);
        }

        /// <summary>
        /// Get distance between two point
        /// </summary>
        /// <param name="point1">Point 1</param>
        /// <param name="point2">Point 2</param>
        /// <returns>Distance between two point</returns>
        private double GetDistance(Point point1, Point point2)
        {
            //pythagorean theorem c^2 = a^2 + b^2
            //thus c = square root(a^2 + b^2)
            double a = (double)(point2.X - point1.X);
            double b = (double)(point2.Y - point1.Y);

            return Math.Sqrt(a * a + b * b);
        }
    }
}