aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Messages/MachineConnectionChangedMessage.cs
blob: af36f2edf614fca74590dcc8ceb42279829ced4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.Integration.ExternalBridge;

namespace Tango.MachineStudio.Common.Messages
{
    public class MachineConnectionChangedMessage : IStudioMessage
    {
        public IExternalBridgeClient Machine { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using RealTimeGraphX.EventArguments;

namespace RealTimeGraphX
{
    /// <summary>
    /// Represents an <see cref="IGraphPainter"/> base class.
    /// </summary>
    /// <typeparam name="TDataSeries">The type of the data series.</typeparam>
    /// <typeparam name="TImage">The type of the image.</typeparam>
    /// <seealso cref="RealTimeGraphX.GraphInputOutputComponentBase{RealTimeGraphX.IGraphRenderer{TDataSeries}, RealTimeGraphX.IGraphSurface}" />
    /// <seealso cref="RealTimeGraphX.IGraphPainter{TDataSeries, TImage}" />
    public abstract class GraphPainterBase<TDataSeries, TImage> : GraphInputOutputComponentBase<IGraphRenderer<TDataSeries>, IGraphSurface>, IGraphPainter<TDataSeries, TImage> where TDataSeries : IGraphDataSeries
    {
        private bool _size_changed;

        #region Events

        /// <summary>
        /// Occurs when the painter has a new graph image available.
        /// </summary>
        public event EventHandler<PaintingCompletedEventArgs<TImage>> PaintingCompleted;

        /// <summary>
        /// Occurs when the current painter transformation (Scale/Translate) has changed.
        /// </summary>
        public event EventHandler<TransformChangedEventArgs> TransformChanged;

        /// <summary>
        /// Occurs when the current virtual (effective minimum/maximum after transformation) x-axis minimum/maximum has changed.
        /// </summary>
        public event EventHandler<RangeChangedEventArgs> VirtualRangeXChanged;

        /// <summary>
        /// Occurs when the current virtual (effective minimum/maximum after transformation) y-axis minimum/maximum has changed.
        /// </summary>
        public event EventHandler<RangeChangedEventArgs> VirtualRangeYChanged;

        #endregion

        #region Properties

        /// <summary>
        /// Gets the current graph image.
        /// </summary>
        public abstract TImage Image { get; protected set; }

        private GraphTransform _transform;
        /// <summary>
        /// Gets the current painter transform object.
        /// The transform object is constructed based on the current <see cref="ZoomRect" />.
        /// </summary>
        public GraphTransform Transform
        {
            get
            {
                return _transform;
            }
            private set
            {
                _transform = value;
                RaisePropertyChangedAuto();
            }
        }

        private GraphRect _zoomRect;
        /// <summary>
        /// Gets the last zooming rectangle that was passed on <see cref="SetZoomRect(GraphRect)" />.
        /// </summary>
        public GraphRect ZoomRect
        {
            get
            {
                return _zoomRect;
            }
            private set
            {
                _zoomRect = value;
                RaisePropertyChangedAuto();
            }
        }

        private GraphDataPointBase _virtualMinimumX;
        /// <summary>
        /// Gets the current virtual (effective minimum/maximum after transformation) x-axis minimum.
        /// </summary>
        public GraphDataPointBase VirtualMinimumX
        {
            get
            {
                return _virtualMinimumX;
            }
            private set
            {
                _virtualMinimumX = value;
                RaisePropertyChangedAuto();
            }
        }

        private GraphDataPointBase _virtualMaximumX;
        /// <summary>
        /// Gets the current virtual (effective minimum/maximum after transformation) x-axis maximum.
        /// </summary>
        public GraphDataPointBase VirtualMaximumX
        {
            get
            {
                return _virtualMaximumX;
            }
            private set
            {
                _virtualMaximumX = value;
                RaisePropertyChangedAuto();
            }
        }

        private GraphDataPointBase _virtualMinimumY;
        /// <summary>
        /// Gets the current virtual (effective minimum/maximum after transformation) y-axis minimum.
        /// </summary>
        public GraphDataPointBase VirtualMinimumY
        {
            get
            {
                return _virtualMinimumY;
            }
            private set
            {
                _virtualMinimumY = value;
                RaisePropertyChangedAuto();
            }
        }

        private GraphDataPointBase _virtualMaximumY;
        /// <summary>
        /// Gets the current virtual (effective minimum/maximum after transformation) y-axis maximum.
        /// </summary>
        public GraphDataPointBase VirtualMaximumY
        {
            get
            {
                return _virtualMaximumY;
            }
            private set
            {
                _virtualMaximumY = value;
                RaisePropertyChangedAuto();
            }
        }

        /// <summary>
        /// Gets the width of the connected output surface.
        /// </summary>
        public double SurfaceWidth { get; private set; }

        /// <summary>
        /// Gets the height of the connected output surface.
        /// </summary>
        public double SurfaceHeight { get; private set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="GraphPainterBase"/> class.
        /// </summary>
        public GraphPainterBase()
        {
            Transform = new GraphTransform();

            //VirtualMinimumX = GraphDataPointHelper.Init<XDataPoint>();
            //VirtualMinimumY = GraphDataPointHelper.Init<YDataPoint>();
            //VirtualMaximumX = GraphDataPointHelper.Init<XDataPoint>();
            //VirtualMaximumY = GraphDataPointHelper.Init<YDataPoint>();
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Sets the painter zooming rectangle.
        /// The zoom rectangle must be smaller than the size of the connected <see cref="IGraphSurface" /> size.
        /// </summary>
        /// <param name="rect">The rectangle.</param>
        public void SetZoomRect(GraphRect rect)
        {
            ZoomRect = rect;
            Input.Invalidate();
        }

        /// <summary>
        /// Resets the painter zooming rectangle.
        /// </summary>
        public void ResetZoomRect()
        {
            ZoomRect = new GraphRect();
            OnVirtualRangeXChanged();
            OnVirtualRangeYChanged();
            Input.Invalidate();
        }

        /// <param name="seriesCollection">The entire series collection.</param>
        /// <param name="series">The data series.</param>
        /// <param name="points">The points.</param>
        public void Draw(IEnumerable<TDataSeries> seriesCollection, TDataSeries series, IEnumerable<GraphPoint> points)
        {
            OnDraw(seriesCollection, series, points, _size_changed);
            _size_changed = false;
        }

        #endregion

        #region Protected Methods

        /// <summary>
        /// Called when the connected input <see cref="IGraphRenderer"/> invoked the <see cref="Draw(GraphDataSeries, IEnumerable{GraphPoint})"/> method.
        /// </summary>
        /// <param name="series">The series to draw.</param>
        /// <param name="points">The points to draw.</param>
        /// <param name="sizeChanged">Specifies whether there is a need to reinitialize the image because surface size change.</param>
        protected abstract void OnDraw(IEnumerable<TDataSeries> seriesCollection, TDataSeries series, IEnumerable<GraphPoint> points, bool sizeChanged);

        /// <summary>
        /// Called when the connected surface size had changed.
        /// </summary>
        /// <param name="e">The <see cref="SurfaceSizeChangedEventArgs"/> instance containing the event data.</param>
        protected virtual void OnSurfaceSizeChanged(SurfaceSizeChangedEventArgs e)
        {
            SurfaceWidth = e.Width;
            SurfaceHeight = e.Height;
        }

        /// <summary>
        /// Called when the virtual x-axis minimum/maximum range has changed.
        /// </summary>
        protected virtual void OnVirtualRangeXChanged()
        {
            if (ZoomRect.Width > 0 || ZoomRect.Height > 0)
            {
                var zoom_rect_left_percentage = ZoomRect.Left / Output.SurfaceWidth;
                var zoom_rect_right_percentage = ZoomRect.Right / Output.SurfaceWidth;

                VirtualMinimumX = GraphDataPointHelper.ComputeAbsolutePosition(Input.EffectiveMinimumX, Input.EffectiveMaximumX, zoom_rect_left_percentage) as GraphDataPointBase;
                VirtualMaximumX = GraphDataPointHelper.ComputeAbsolutePosition(Input.EffectiveMinimumX, Input.EffectiveMaximumX, zoom_rect_right_percentage) as GraphDataPointBase;
            }
            else
            {
                VirtualMinimumX = Input.EffectiveMinimumX;
                VirtualMaximumX = Input.EffectiveMaximumX;
            }

            VirtualRangeXChanged?.Invoke(this, new RangeChangedEventArgs(VirtualMinimumX, VirtualMaximumX));
        }

        /// <summary>
        /// Called when the virtual y-axis minimum/maximum range has changed.
        /// </summary>
        protected virtual void OnVirtualRangeYChanged()
        {
            if (ZoomRect.Width > 0 || ZoomRect.Height > 0)
            {
                var zoom_rect_top_percentage = ZoomRect.Top / Output.SurfaceHeight;
                var zoom_rect_bottom_percentage = ZoomRect.Bottom / Output.SurfaceHeight;

                VirtualMinimumY = Input.EffectiveMaximumY - GraphDataPointHelper.ComputeAbsolutePosition(Input.EffectiveMinimumY, Input.EffectiveMaximumY, zoom_rect_bottom_percentage) as GraphDataPointBase;
                VirtualMaximumY = Input.EffectiveMaximumY - GraphDataPointHelper.ComputeAbsolutePosition(Input.EffectiveMinimumY, Input.EffectiveMaximumY, zoom_rect_top_percentage) as GraphDataPointBase;
            }
            else
            {
                VirtualMinimumY = Input.EffectiveMinimumY;
                VirtualMaximumY = Input.EffectiveMaximumY;
            }

            VirtualRangeYChanged?.Invoke(this, new RangeChangedEventArgs(VirtualMinimumY, VirtualMaximumY));
        }

        /// <summary>
        /// Called when the painter transformation has changed.
        /// </summary>
        /// <param name="e">The <see cref="TransformChangedEventArgs"/> instance containing the event data.</param>
        protected virtual void OnTransformChanged(TransformChangedEventArgs e)
        {
            Transform = e.Transform;
            TransformChanged?.Invoke(this, e);
        }

        /// <summary>
        /// Returns a closed polygon points which can be used to fill a graph polygon/>.
        /// </summary>
        /// <param name="points">The points.</param>
        /// <returns></returns>
        protected virtual IEnumerable<GraphPoint> GetFillPoints(IEnumerable<GraphPoint> points)
        {
            List<GraphPoint> closed = points.ToList();
            closed.Add(new GraphPoint(points.Last().X, SurfaceWidth));
            closed.Add(new GraphPoint(0, SurfaceHeight));
            return closed;
        }

        /// <summary>
        /// Raises the <see cref="PaintingCompletedEventArgs{TImage}"/> event.
        /// </summary>
        /// <param name="image">The image.</param>
        protected virtual void OnPaintingCompleted(TImage image)
        {
            Output.InvokeOnSurface(() =>
            {
                Image = image;
                PaintingCompleted?.Invoke(this, new PaintingCompletedEventArgs<TImage>() { Image = image });
            });
        }

        #endregion

        #region Event Handlers

        private void Input_EffectiveRangeYChanged(object sender, RangeChangedEventArgs e)
        {
            OnVirtualRangeYChanged();
        }

        private void Input_EffectiveRangeXChanged(object sender, RangeChangedEventArgs e)
        {
            OnVirtualRangeXChanged();
        }

        private void _surface_SurfaceSizeChanged(object sender, SurfaceSizeChangedEventArgs e)
        {
            _size_changed = true;
            OnSurfaceSizeChanged(e);
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Connects this painter to the specified <see cref="IGraphRenderer"/>.
        /// </summary>
        /// <param name="renderer">The renderer.</param>
        /// <param name="fromInput">Specifies whether this call was made from the input <see cref="IGraphRenderer"/>.</param>
        public override void ConnectInput(IGraphRenderer<TDataSeries> renderer, bool fromInput = false)
        {
            renderer.ThrowIfNull("Cannot connect a null renderer.");

            DisconnectInput();

            Input = renderer;

            if (!fromInput)
            {
                Input.ConnectOutput(this, true);
            }

            Input.EffectiveRangeXChanged += Input_EffectiveRangeXChanged;
            Input.EffectiveRangeYChanged += Input_EffectiveRangeYChanged;
        }

        /// <summary>
        /// Disconnects the connected input <see cref="IGraphRenderer"/>.
        /// </summary>
        /// <param name="fromInput">Specifies whether this call was made from the connected input <see cref="IGraphRenderer"/>.</param>
        public override void DisconnectInput(bool fromInput = false)
        {
            if (Input != null)
            {
                if (!fromInput)
                {
                    Input.DisconnectOutput(true);
                }

                Input.EffectiveRangeXChanged -= Input_EffectiveRangeXChanged;
                Input.EffectiveRangeYChanged -= Input_EffectiveRangeYChanged;

                Input = null;
            }
        }

        /// <summary>
        /// Connects this painter to the specified <see cref="IGraphSurface"/>.
        /// </summary>
        /// <param name="surface">The graph surface.</param>
        /// <param name="fromOutput">Specifies whether this call was made from the connected output <see cref="IGraphSurface"/>.</param>
        public override void ConnectOutput(IGraphSurface surface, bool fromOutput = false)
        {
            surface.ThrowIfNull("Cannot connect a null surface.");

            DisconnectOutput();

            Output = surface;

            Output.SurfaceSizeChanged += _surface_SurfaceSizeChanged;

            if (!fromOutput)
            {
                Output.ConnectInput(this, true);
            }

            _size_changed = true;
        }

        /// <summary>
        /// Disconnects this painter from the current connected <see cref="IGraphSurface"/>.
        /// </summary>
        /// <param name="fromOutput">Specifies whether this call was made the output <see cref="IGraphSurface"/>.</param>
        public override void DisconnectOutput(bool fromOutput = false)
        {
            if (Output != null)
            {
                if (!fromOutput)
                {
                    Output.DisconnectInput(true);
                }

                Output.SurfaceSizeChanged -= _surface_SurfaceSizeChanged;

                Output = null;
            }
        }

        #endregion
    }
}