/// <summary>
		/// Inserts a channel at the specified index.
		/// </summary>
		public void Insert( int index, Channel value )
		{
			if (value == null || index >= List.Count)
				return;

			List.Insert( index, value );
		}
        /// <summary>
		/// Add a new <c>Channel</c> to the collection.
		/// </summary>
        /// <returns>The index of the added channel.</returns>
		public int Add(Channel channel)
		{
			if (channel == null)
				throw new ArgumentNullException ();

			return( List.Add( channel ) );
		}
		/// <summary>
		/// Removes the specified channel from the plotter.
		/// </summary>
		public void Remove ( Channel value )
		{
			if (value == null)
				return;

			if (! List.Contains (value))
				throw new ArgumentException ();

			for (int i = 0; i < List.Count; i ++)
			{
				if ( ((Channel) List[i]).YAxisName == value.YAxisName)
				{
					List.RemoveAt (i);
					break;
				}
			}
		}
Exemple #4
0
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <param name="channel">Channel reference.</param>
		public Cursor(Channel channel)
		{						
			m_Channel = channel;
        }
Exemple #5
0
        /// <summary>
        /// Find the engineering value corresponding to the specified time. If an entry corresponding to the specified time does not exist, the value corresponding to 
        /// the nearest valid time entry which is greater than the specified time is returned.   
        /// </summary>
        /// <param name="timeInMs">The time, in ms, from the start of the plot.</param>
        /// <param name="channel">The channel reference that is currently being plotted.</param>
        /// <returns>The engineering value corresponding to the specified time or, if this does not exist, the value corresponding to the nearest valid time entry which 
        /// is greater than the specified time. If no entry for the specified time exists and there are no valid time entries that are greater than the specified time 
        /// Float.NaN is returned.</returns>
        protected float FindY(long timeInMs, Channel channel)
        {
            // The array index of the Points generic list where the specified time is located.
            int index;

            // Search the List for an entry containing the specified time. The BinarySearch() call returns the zero-based index of the entry corresponding to the 
            // specified time, if it exists; otherwise, it will return a negative number that is the bitwise complement of the index of the entry corresponding to the 
            // time that is the nearest to but greater than the specified time. If no entry is found, the bitwise complement of the Count is returned. 
            index = channel.X.BinarySearch(timeInMs);

            // Default to 'Not a Number'.
            float y = float.NaN;
            if (index >= 0)
            {
                // An entry matching the specified time was found, return the corresponding Y value.
                y = channel.Points[index].Y;
            }
            else
            {
                // Check whether a valid entry exists. 
                if (index != ~channel.X.Count)
				{
                    // Get the Y value associated with the entry corresponding to the time that that is nearest to but greater than the specified time.
					y = channel.Points[~index].Y;
				}
				else
				{
					// Do nothing, y stays NaN.
				}
            }
            return y;
        }
Exemple #6
0
        /// <summary>
        /// Convert the specified pixel position into the corresponding PointF.X (time, in ms, since the start of the plot) and PointF.Y 
        /// (engineering value) for the specified channel. Used when the mouse coordinates need to be converted to real values.
        /// </summary>
        /// <remarks>
        /// GraphArea.Top, GraphArea.Left corresponds to the pixel coordinates 0,0.
        /// </remarks>
        /// <param name="channel">The channel reference.</param>
        /// <param name="xInPixel">The X pixel value.</param>
        /// <param name="yInPixel">The Y pixel value.</param>
        /// <returns>A PointF value containing the converted time, in ms, from the start of the plot and the corresponding engineering value.</returns>
        protected PointF GetValueFromPixel(Channel channel, int xInPixel, int yInPixel)
        {
            // yInValue.
            float yAbsolute = (float)(m_GraphArea.Bottom - yInPixel) / (float)m_GraphArea.Height;
            float yRange = channel.MaximumValue - channel.MinimumValue;
            float yInValue = channel.MinimumValue + (yAbsolute * yRange);

            // xInValue.
            float xOffsetPixel = (float)(xInPixel - m_GraphArea.Left) / (float)m_GraphArea.Width;
            int xRangeInMs = (int)(m_XRange.Duration().Ticks / TimeSpan.TicksPerMillisecond);
            float xInValue = (xOffsetPixel * (float)xRangeInMs);

            return new PointF(xInValue, yInValue);
        }
Exemple #7
0
        /// <summary>
        /// Convert the PointF.X and PoinF.Y values (time and engineering value) for a particular channel into the relative pixel values for the GraphArea.
        /// </summary>
        /// <remarks>
        /// GraphArea.Top, GraphArea.Left corresponds to the pixel coordinates 0,0.
        /// </remarks>
        /// <param name="channel">The channel reference.</param>
        /// <param name="xInValue">The PointF.X value i.e. time, in ms, since the start of the plot.</param>
        /// <param name="yInValue">The PointF.Y value i.e. engineering value.</param>
        /// <returns>The pixel coordinates.</returns>
        protected Point GetPixelFromValue(Channel channel, int xInValue, float yInValue)
        {
            // yInPixel.
            float yRange = channel.MaximumValue - channel.MinimumValue;
            float y = (yInValue - channel.MinimumValue) / yRange;
            int yInPixel = m_GraphArea.Bottom - (int)(y * (float)m_GraphArea.Height);

            // xInPixel.
            int xOffsetValue = xInValue;
            xOffsetValue -= (m_LeftDisplayLimit);
            int xRangeInMs = (int)(m_XRange.Duration().Ticks / TimeSpan.TicksPerMillisecond);
            float xOffsetAbs = (float)((float)xOffsetValue / (float)xRangeInMs);
            int xInPixel = m_GraphArea.Left + (int)(xOffsetAbs * m_GraphArea.Width);

            return new Point(xInPixel, yInPixel);
        }
Exemple #8
0
        /// <summary>
        /// Plot the points contained within the specified ArrayList[]. Each element of ArrayList[] contains a continuous set of points to be plotted. 
        /// If there are no gaps in the data to be plotted the array will contain a single element.
        /// </summary>
        /// <param name="graphics">Reference to the The GDI+ drawing surface.</param>
        /// <param name="activeChannel">True, if the specified channel is the active channel; otherwise false.</param>
        /// <param name="channel">The channel reference.</param>
        /// <param name="pointsList">An array of ArrayLists where each element of the array contains the points to be plotted for each continuous block of data.</param>
        private void PlotPointsListArray(Graphics graphics, bool activeChannel, Channel channel, ArrayList[] pointsList)
        {
            // Skip if the Dispose() method has been called.
            if (IsDisposed)
            {
                return;
            }

            // Convert the ArrayList[] of pixel coordinates to a jagged array i.e. an array whose elements are an array, ready for plotting.
            Point[][] pointsToPlot = new Point[channel.BreakPoint.Count + 1][];
            for (int block = 0; block <= channel.BreakPoint.Count; block++)
            {
                pointsToPlot[block] = new Point[pointsList[block].Count];
                for (int index = 0; index < pointsList[block].Count; index++)
                {
                    pointsToPlot[block][index] = (Point)pointsList[block][index];
                }
            }

            graphics.SetClip(m_GraphArea);

            try
            {
                // Plot each block of pixel coordinates.
                for (int block = 0; block <= channel.BreakPoint.Count; block++)
                {
                    // Skip if there aren't at least 2 points to plot.
                    if (pointsToPlot[block].Length < 2)
                    {
                        continue;
                    }

                    if (activeChannel)
                    {
                        graphics.DrawLines(new Pen(channel.ChannelColor, 1.5F), pointsToPlot[block]);
                    }
                    else
                    {
                        graphics.DrawLines(new Pen(channel.ChannelColor, 1.5F), pointsToPlot[block]);
                    }
                }
            }
            catch (Exception)
            {
                // -------------------------------------------------
                // Catch the exception and report this to the user.
                // -------------------------------------------------
                m_InvalidData = true;

                string statusMessage = Resources.SMPlotInvalid;
                SizeF stringSize = graphics.MeasureString(statusMessage, Font);
                int top = m_GraphArea.Bottom - Font.Height - StatusMessageBorder;
                int left = (int)((m_GraphArea.Width - (int)stringSize.Width) / 2);
                using (Brush textBrush = new SolidBrush(Color.Red))
                {
                    graphics.DrawString(statusMessage, Font, textBrush, left, top);
                }
            }
        }
Exemple #9
0
        /// <summary>
        /// Create a jagged array of ArrayLists containing the points to be plotted for each block of data.
        /// </summary>
        /// <param name="channel">The channel reference.</param>
        /// <returns>An array of ArrayLists containing the points to be plotted for each block.</returns>
        private ArrayList[] AddToPointsListArray(Channel channel)
        {
            // Create an ArrayList of PointF values for each group of PointF values separated by a break point e.g. zero breakpoints would
            // require a single list, 1 break point would require two lists etc, where each break point specifies the elapsed time value 
            // corresponding to a plot entry where the pen colour is to be set to transparent between this particular plot entry and the next 
            // plot entry. Break points are associated with min/hour/day logs and RTD logs and record periods where the unit has been powered down. 
            ArrayList[] pointsList = new ArrayList[channel.BreakPoint.Count + 1];

            for (int block = 0; block <= channel.BreakPoint.Count; block++)
            {
                pointsList[block] = new ArrayList();
            }

            // Local variable to store the current entry of the generic list associated with the channel.
            PointF pointStored = new PointF();

            // Local variable to store the pixel value corresponding to the current entry of the generic list associated with te channel.
            Point p;
            if (m_CurrentState == PlotterState.Stopped)
            {
                // The index of the current block of data.
                int blockIndex = 0;
                for (int index = 0; index < channel.Points.Count; index++)
                {
                    // Get the current entry of the generic list.
                    pointStored = channel.Points[index];

                    // Convert the PointF values to pixel coordinates.
                    p = GetPixelFromValue(channel, (int)pointStored.X, pointStored.Y);
                    pointsList[blockIndex].Add(p);

                    // Check if the generic list contains further breakpoints.
                    if (blockIndex < channel.BreakPoint.Count)
                    {
                        // If the current time value corresponds to a latest break point, add the remaining data values to the next 
                        // pointsList element.
                        if (pointStored.X == channel.BreakPoint[blockIndex])
                        {
                            pointsList[blockIndex].Add(p);
                            blockIndex++;
                        }
                    }
                }
            }
            else
            {
                // Note: There are no break points associated with real time mode.
                for (int index = 0; index < channel.Points.Count - m_PointsToRemove; index++)
                {
                    pointStored = (PointF)channel.Points[index + m_PointsToRemove];

                    // Convert the PointF values to pixel coordinates.
                    p = GetPixelFromValue(channel, (int)pointStored.X, pointStored.Y);
                    pointsList[0].Add(p);
                }
            }
            return pointsList;
        }
Exemple #10
0
        /// <summary>
        /// Plot the points contained within the specified ArrayList[]. Each element of ArrayList[] contains a continuous set of points to be plotted. 
        /// If there are no gaps in the data to be plotted the array will contain a single element.
        /// </summary>
        /// <param name="graphics">Reference to the The GDI+ drawing surface.</param>
        /// <param name="channel">The channel reference.</param>
        /// <param name="pointsList">An array of ArrayLists where each element of the array contains the points to be plotted for each continuous block of data.</param>
        private void PlotPointsListArray(Graphics graphics, Channel channel, ArrayList[] pointsList)
        {
            // Skip if the Dispose() method has been called.
            if (IsDisposed)
            {
                return;
            }

            // Convert the ArrayList[] of pixel coordinates to a jagged array i.e. an array whose elements are an array, ready for plotting.
            Point p;
            Point[][] pointsToPlot = new Point[channel.BreakPoint.Count + 1][];
            for (int block = 0; block <= channel.BreakPoint.Count; block++)
            {
                pointsToPlot[block] = new Point[pointsList[block].Count];
                for (int index = 0; index < pointsList[block].Count; index++)
                {
                    pointsToPlot[block][index] = (Point)pointsList[block][index];
                }
            }

            graphics.SetClip(m_GraphArea);

            // Plot each block of pixel coordinates.
            Point pointFloatRepresentationOfSet = GetPixelFromValue(channel, 0, Channel.FloatRepresentationOfSet);

            // The pen colour.
            try
            {
                Color color;
                for (int block = 0; block <= channel.BreakPoint.Count; block++)
                {
                    for (int index = 1; index < pointsToPlot[block].Length; index++)
                    {
                        // Skip if there aren't at least 2 points to plot.
                        if (pointsToPlot[block].Length <= 1)
                        {
                            continue;
                        }

                        p = pointsToPlot[block][index];

                        // Set the pen colour depending on the active alarm state of the plot and the current value; clear: green, alarm: red.
                        if (m_AlarmState == true)
                        {
                            color = (p.Y == pointFloatRepresentationOfSet.Y) ? m_AlarmStatePlotColor : m_ClearStatePlotColor;
                        }
                        else
                        {
                            color = (p.Y == pointFloatRepresentationOfSet.Y) ? m_ClearStatePlotColor : m_AlarmStatePlotColor;
                        }

                        graphics.DrawLine(new Pen(color, 1.5F), pointsToPlot[block][index - 1], pointsToPlot[block][index]);
                    }
                }
            }
            catch (Exception)
            {
                // -------------------------------------------------
                // Catch the exception and report this to the user.
                // -------------------------------------------------
                m_InvalidData = true;

                string statusMessage = Resources.SMPlotInvalid;
                SizeF stringSize = graphics.MeasureString(statusMessage, Font);
                int top = m_GraphArea.Bottom - Font.Height - StatusMessageBorder;
                int left = (int)((m_GraphArea.Width - (int)stringSize.Width) / 2);
                using (Brush textBrush = new SolidBrush(Color.Red))
                {
                    graphics.DrawString(statusMessage, Font, textBrush, left, top);
                }
            }
            return;
        }
Exemple #11
0
        /// <summary>
        /// Create an array of ArrayLists containing the points to be plotted for each block of data. This method also adds the required points 
        /// into the ArrayList[] so that the digital state transitions appear as a vertical line.
        /// </summary>
        /// <param name="channel">The channel reference.</param>
        /// <returns>An array of ArrayLists containing the points to be plotted for each block.</returns>
        private ArrayList[] AddToPointsListArray(Channel channel)
        {
            // Create an ArrayList of PointF values for each group of PointF values separated by a break point e.g. zero breakpoints would
            // require a single list, 1 break point would require two lists etc, where each break point specifies the elapsed time value 
            // corresponding to a plot entry where the pen colour is to be set to transparent between this particular plot entry and the next 
            // plot entry. Break points are associated with min/hour/day logs and RTD logs and record periods where the unit has been powered down. 
            ArrayList[] pointsList = new ArrayList[channel.BreakPoint.Count + 1];
            for (int block = 0; block <= channel.BreakPoint.Count; block++)
            {
                pointsList[block] = new ArrayList();
            }

            // -----------------------------------------------------------------------------------------------------------------
            // Populate the ArrayList[] with the points to be plotted. For state transitions don't draw directly to the next point, instead, make transition edges
            // vertical. Also  only include points where transitions occur, this improves the processing time of the method.
            // -----------------------------------------------------------------------------------------------------------------

            // Local variable to store the current element of the generic list of Points associated with the channel.
            PointF pointStored = new PointF();

            // Local variable to store the pixel value corresponding to the current element of the generic list of Points associated with the channel.
            Point p;

            // Local variable to store the previous element of the generic list of Points associated with the channel.
            PointF pointStoredPrev = new PointF();
            if (m_CurrentState == PlotterState.Stopped)
            {
                // The index of the current block of data.
                int blockIndex = 0;

                // True, if this is the first entry of the generic list; otherwise, false.
                bool firstEntry = true;

                // True, if this is the first entry of a new block;
                bool newBlock = false;
                for (int index = 0; index < channel.Points.Count; index++ )
                {
                    // Get the current entry of the generic list.
                    pointStored = channel.Points[index];

                    #region - First Entry -
                    // Check whether this is the first entry in the generic list.
                    if (firstEntry)
                    {
                        firstEntry = false;

                        // Add the pixel value corresponding to the first entry of the generic list to the ArrayList[].
                        p = GetPixelFromValue(channel, (int)pointStored.X, pointStored.Y);
                        pointsList[blockIndex].Add(p);

                        // Check if the generic list contains further breakpoints.
                        if (blockIndex < channel.BreakPoint.Count)
                        {
                            // If the current time value corresponds to a break point increment the block index.
                            if (pointStored.X == channel.BreakPoint[blockIndex])
                            {
                                blockIndex++;

                                // Ensure that the next entry in the generic list is recorded to the next ArrayList[] element.
                                newBlock = true;
                            }
                        }
                    }
                    #endregion - First Entry -

                    #region - Last Entry -
                    else if (index == channel.Points.Count - 1)                   // Check whether this is the last entry in the generic list.
                    {
                        // Add the pixel value corresponding to the current entry of the generic list to the ArrayList[] and include an interim plot value so that
                        // the transition is drawn as a vertical line if a state change has occurred.
                        if (pointStored.Y != pointStoredPrev.Y)
                        {
                            // Add interim plot value so that transition is drawn as a vertical line.
                            p = GetPixelFromValue(channel, (int)pointStored.X, pointStoredPrev.Y);
                            pointsList[blockIndex].Add(p);
                        }
                        p = GetPixelFromValue(channel, (int)pointStored.X, pointStored.Y);
                        pointsList[blockIndex].Add(p);
                    }
                    #endregion - Last Entry -

                    #region - New Block -
                    else if (newBlock)
                    {
                        newBlock = false;

                        // Add the pixel value corresponding to the current entry of the generic list to the ArrayList[] and include an interim plot value so that the
                        // transition is drawn as a vertical line if a state change has occurred.
                        if (pointStored.Y != pointStoredPrev.Y)
                        {
                            // Add interim plot value so that transition is drawn as a vertical line.
                            p = GetPixelFromValue(channel, (int)pointStored.X, pointStoredPrev.Y);
                            pointsList[blockIndex].Add(p);
                        }
                        p = GetPixelFromValue(channel, (int)pointStored.X, pointStored.Y);
                        pointsList[blockIndex].Add(p);

                        // Check if the generic list contains further breakpoints.
                        if (blockIndex < channel.BreakPoint.Count)
                        {
                            // If the current time value corresponds to a break point increment the block index.
                            if (pointStored.X == channel.BreakPoint[blockIndex])
                            {
                                blockIndex++;

                                // Ensure that the next entry in the generic list is recorded to the next ArrayList[] element.
                                newBlock = true;
                            }
                        }
                    }
                    #endregion - New Block -

                    #region - Process Entry -
                    else
                    {
                        // Only record values where the state of the digital IO has changed.
                        if (pointStored.Y != pointStoredPrev.Y)
                        {
                            // A transition has occurred, add the interim plot value so that transition is drawn as a vertical line.
                            p = GetPixelFromValue(channel, (int)pointStored.X, pointStoredPrev.Y);
                            pointsList[blockIndex].Add(p);

                            p = GetPixelFromValue(channel, (int)pointStored.X, pointStored.Y);
                            pointsList[blockIndex].Add(p);

                            // Check if the generic list contains further breakpoints.
                            if (blockIndex < channel.BreakPoint.Count)
                            {
                                // If the current time value corresponds to a break point increment the block index.
                                if (pointStored.X == channel.BreakPoint[blockIndex])
                                {
                                    blockIndex++;
                                    newBlock = true;
                                }
                            }

                        }
                        else
                        {
                            if (blockIndex < channel.BreakPoint.Count)  // Check if the generic list contains further breakpoints.
                            {
                                // If the current time value corresponds to a break point increment the block index and add the pixel value corresponding to the 
                                // current entry of the generic list to the ArrayList[].
                                if (pointStored.X == channel.BreakPoint[blockIndex])
                                {
                                    // Add the pixel value corresponding to the current entry of the generic list to the ArrayList[].
                                    p = GetPixelFromValue(channel, (int)pointStored.X, pointStored.Y);
                                    pointsList[blockIndex].Add(p);

                                    blockIndex++;
                                    newBlock = true;
                                }
                            }
                        }
                    }

                    // Copy the current value to the previous value in order to detect state changes.
                    pointStoredPrev = pointStored;
                    #endregion - Process Entry -
                }
            }
            else
            {
                // --------------------------------------------------------------
                // Note: There are no break points associated with real time mode.
                // --------------------------------------------------------------
                for (int j = 0; j < channel.Points.Count - m_PointsToRemove; j++)
                {
                    pointStored = (PointF)channel.Points[j + m_PointsToRemove];
                    if ((j != 0) && (pointStoredPrev.Y != pointStored.Y))
                    {
                        // Transition has occurred, add interim plot value so that transition is drawn as a vertical line.
                        p = GetPixelFromValue(channel, (int)pointStored.X, pointStoredPrev.Y);
                        pointsList[0].Add(p);
                    }
                    p = GetPixelFromValue(channel, (int)pointStored.X, pointStored.Y);
                    pointsList[0].Add(p);
                    pointStoredPrev = pointStored;
                }
            }
            return pointsList;
        }
		/// <summary>
		/// Checks whether the specified channel is contained within the collection.
		/// </summary>
		/// <param name="channel">Reference to the channel that is to be checked.</param>
		/// <returns>True, if the specified reference is contained within the collection; otherwise, false.</returns>
		public bool Contains( Channel channel )
		{
			// If value is not of type Channel, this will return false.
			return( List.Contains( channel ) );
        }
		/// <summary>
		/// Returns the index of the specified channel.
		/// </summary>
        /// <returns>The index of the specified channel.</returns>
		public int IndexOf( Channel value )
		{
			return( List.IndexOf( value ) );
		}