aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Helpers/GraphsHelper.cs
blob: fa80f90dd376ef142a722a65a34080b4a68e239b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.MachineStudio.Common;
using Tango.Settings;

namespace Tango.MachineStudio.Technician.Helpers
{
    /// <summary>
    /// Contains RealTimeGraphEx helper methods.
    /// </summary>
    public static class GraphsHelper
    {
        /// <summary>
        /// Gets the maximum points graph points by correlating between seconds duration from settings and expected graph points per frame.
        /// </summary>
        /// <param name="pointsPerFrame">Length of graph points per frame.</param>
        /// <returns></returns>
        public static int GetMaxPoints(double pointsPerFrame)
        {
            try
            {
                var settings = SettingsManager.Default.GetOrCreate<TechnicianModuleSettings>();
                double seconds = settings.GraphsDuration;
                double pullRate = settings.DiagnosticsResponseIntervalMilli;
                return (int)(((pullRate * pointsPerFrame * 10 * seconds) * (10 / pullRate)) * 0.65);
            }
            catch (Exception)
            {
                return 300;
            }
        }
    }
}
xception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
using RealTimeGraphEx.Controllers;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace RealTimeGraphEx.ReachGraphs
{
    public class RealTimeGraphExReachVUMeter : RealTimeGraphExBase
    {
        #region Protected Fields

        protected int updateCounter;
        protected Rectangle rectangle;
        protected double lastValue;

        #endregion

        #region Cross Thread Fields

        protected Brush _stroke;
        protected Brush _fill;
        protected GraphController _graphController;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the graph strokes color.
        /// </summary>
        public Brush Stroke
        {
            get { return (Brush)GetValue(StrokeProperty); }
            set { SetValue(StrokeProperty, value); }
        }
        public static readonly DependencyProperty StrokeProperty =
            DependencyProperty.Register("Stroke", typeof(Brush), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(Brushes.Black, new PropertyChangedCallback(CrossModelChanged)));

        /// <summary>
        /// Gets or sets the graph fill color.
        /// </summary>
        public Brush Fill
        {
            get { return (Brush)GetValue(FillProperty); }
            set { SetValue(FillProperty, value); }
        }
        public static readonly DependencyProperty FillProperty =
            DependencyProperty.Register("Fill", typeof(Brush), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(Brushes.Gray, new PropertyChangedCallback(CrossModelChanged)));

        /// <summary>
        /// Gets or sets the IDataSeries used to push data points to the graph.
        /// </summary>
        public GraphController Controller
        {
            get { return (GraphController)GetValue(ControllerProperty); }
            set { SetValue(ControllerProperty, value); }
        }
        public static readonly DependencyProperty ControllerProperty =
            DependencyProperty.Register("Controller", typeof(GraphController), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(null, new PropertyChangedCallback(GraphControllerChanged)));
        private static void GraphControllerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = d as RealTimeGraphExReachVUMeter;

            if (control.Controller != null)
            {
                control.Controller.RegisterMethods(control.ClearGraph, control.StartPushThread, control.SetPaused,control.ChangeRenderMode,null);
                control._graphController = control.Controller;
            }
        }

        /// <summary>
        /// Gets or sets the collection of VU range data determines how to fill the VU graph.
        /// </summary>
        public ObservableCollection<Models.RangeData> Ranges
        {
            get { return (ObservableCollection<Models.RangeData>)GetValue(RangesProperty); }
            set { SetValue(RangesProperty, value); }
        }
        public static readonly DependencyProperty RangesProperty =
            DependencyProperty.Register("Ranges", typeof(ObservableCollection<Models.RangeData>), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(null));

        /// <summary>
        /// Gets or sets whether to animate the VU when when it's value doens not change.
        /// </summary>
        public bool Animate
        {
            get { return (bool)GetValue(AnimateProperty); }
            set { SetValue(AnimateProperty, value); }
        }
        public static readonly DependencyProperty AnimateProperty =
            DependencyProperty.Register("Animate", typeof(bool), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(false));

        /// <summary>
        /// Gets or sets the height value to animate when the Animate property is set to true.
        /// </summary>
        public double AnimationAmount
        {
            get { return (double)GetValue(AnimationAmountProperty); }
            set { SetValue(AnimationAmountProperty, value); }
        }
        public static readonly DependencyProperty AnimationAmountProperty =
            DependencyProperty.Register("AnimationAmount", typeof(double), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(10.0));

        /// <summary>
        /// Gets or sets the duration of the animation when the Animate property is set to true.
        /// </summary>
        public Duration AnimationDuration
        {
            get { return (Duration)GetValue(AnimationDurationProperty); }
            set { SetValue(AnimationDurationProperty, value); }
        }
        public static readonly DependencyProperty AnimationDurationProperty =
            DependencyProperty.Register("AnimationDuration", typeof(Duration), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(500))));

        

        

        #endregion

        #region Constructors

        public RealTimeGraphExReachVUMeter()
            : base()
        {
            Ranges = new ObservableCollection<Models.RangeData>();
        }

        #endregion

        #region Override Methods

        protected override void Initialize()
        {
            base.Initialize();

            if (rectangle == null)
            {
                rectangle = new Rectangle() { Tag = "Default" };
                rectangle.Height = 0;
            }

            gridLinesAndImageWrapperGrid.Children.Remove(img);

            if (!gridLinesAndImageWrapperGrid.Children.Contains(rectangle))
            {
                gridLinesAndImageWrapperGrid.Children.Add(rectangle);
            }

            //TODO: Base on developer selection vertical/horizontal VU.
            rectangle.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
            rectangle.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
        }

        protected override void OnSetCrossThreadFields()
        {
            base.OnSetCrossThreadFields();

            this.Dispatcher.Invoke(() =>
            {
                _graphController = Controller;
                _stroke = Stroke;
                _fill = Fill;

                if (rectangle.Tag != null && rectangle.Tag.ToString() == "Default")
                {
                    rectangle.Fill = Fill;
                    rectangle.Stroke = Stroke;
                }

                if (_graphController != null && _graphController.dataSeries != null && _graphController.dataSeries.useFillandStroke)
                {
                    rectangle.Fill = _graphController.dataSeries.fill;
                    rectangle.Stroke = _graphController.dataSeries.stroke;
                }

            }, DispatcherPriority.Send);
        }

        protected override void OnClearGraph()
        {
            base.OnClearGraph();

            this.Dispatcher.Invoke(() =>
            {
                rectangle.BeginAnimation(Rectangle.HeightProperty, null);
                rectangle.Height = 0;
            });
        }

        protected internal override void OnRenderGraph()
        {
            if (_graphController != null && _graphController.dataSeries.Points != null && _graphController.dataSeries.Points.Count > 0 && _width > 1 && _height > 1)
            {
                double value = _graphController.dataSeries.Points[_graphController.dataSeries.Points.Count - 1]; //Get last value.

                if (value == lastValue)
                {
                    _graphController.ClearPoints();
                    return;
                }

                lastValue = value;

                double valuePrecentage = ConvertYToImageY(value);

                updateCounter++;

                if (updateCounter >= 1 && !_isPaused)
                {
                    updateCounter = 0;
                    OnDrawVisuals(valuePrecentage);
                }

                _graphController.ClearPoints();
            }
        }

        #endregion

        #region Virtual Methods

        protected virtual void OnDrawVisuals(double valuePrecentage)
        {
            this.Dispatcher.Invoke(() =>
            {
                rectangle.BeginAnimation(Rectangle.HeightProperty, null);
                rectangle.Height = valuePrecentage;
                rectangle.Fill = GetRectangleBrush();

                if (Animate)
                {
                    DoubleAnimation ani = new DoubleAnimation();
                    ani.CurrentTimeInvalidated += (x, y) =>
                    {
                        rectangle.Fill = GetRectangleBrush();
                    };
                    ani.To = rectangle.Height - AnimationAmount;
                    ani.From = rectangle.Height;
                    ani.RepeatBehavior = RepeatBehavior.Forever;
                    ani.AutoReverse = true;
                    ani.Duration = AnimationDuration;

                    rectangle.BeginAnimation(HeightProperty, ani);
                }
            });
        }

        private Brush GetRectangleBrush()
        {
            if (Ranges != null && Ranges.Count > 0)
            {
                LinearGradientBrush brush = new LinearGradientBrush();
                brush.MappingMode = BrushMappingMode.Absolute;
                brush.StartPoint = new Point(0, _height - rectangle.Height);
                brush.EndPoint = new Point(0, (rectangle.Height * -1));
                brush.Transform = new RotateTransform() { Angle = 180 };

                for (int i = Ranges.Count - 1; i >= 0; i--)
                {
                    var range = Ranges[i];

                    double rangeValuePrecentage = ConvertYToImageY(range.Value);

                    GradientStop stop = new GradientStop();
                    stop.Color = range.Color;
                    stop.Offset = ((rangeValuePrecentage * 100) / _height) / 100;
                    brush.GradientStops.Add(stop);
                }

                return brush;
            }
            else
            {
                return Fill;
            }
        }

        #endregion
    }
}