0

In a program I am currently building, a series of arrays are stored for each trace that is taken of a part. Each trace is composed of several arrays of doubles all with a length of 4096. Up to 4 traces can be taken.

The pertinent array for this issue is the Angle array, which is an array of values interpolated from -90 to 90 degrees over 4096 data points (so approx. .044 degrees per index). This array is plotted on a C# chart control against another array of thickness data (also 4096 points).

My chart control also implements the MouseMove event which draws a cursor attached to the X axis (-90 to 90 degrees) on the chart with an interval of .1. The idea is that when a user mouses over the chart, an annotation will popup at the top of the chart displaying the thickness data for the moused over angle.

In the background, each time the MouseMove event is fired off, the X position of the cursor on the chart is put into a function to find the index of the closest angle in the Angle array of trace 1. Here's the search code:

private int FindIndexOfAngle(double Angle)
{

    int closestX = Array.BinarySearch(Traces[0].AngleArray, Angle);
    if (closestX < 0)
    {
        closestX = ~closestX; // If closestX is bitwise complement of index of next highest value from binary search

        double closestY = Traces[0].AngleArray[closestX] - Angle;
        if (Traces[0].AngleArray[closestX - 1] - Angle < closestY) closestX = closestX - 1;
    }

    return closestX;

}

And here is the chart MouseMove event:

private void chartMain_MouseMove(object sender, MouseEventArgs e)
{

    try
    {
        if (chartMain.Series.Count > 0)
        {
            Point mousePoint = new Point(e.X, e.Y);

            chartMain.ChartAreas[0].CursorX.SetCursorPixelPosition(mousePoint, true);
            double pX = chartMain.ChartAreas[0].CursorX.Position;

            if (pX >= -90 && pX <= 90)
            {
                chartMain.ChartAreas[0].CursorX.LineColor = Color.Red;
                //if (pX == 90) chartMain.ChartAreas[0].CursorX.Position = 89.9;
                RectangleAnnotation anno = new RectangleAnnotation();

                int index = FindIndexOfAngle(pX);

                anno.Text = pX.ToString("0.00") + " degrees";

                if (Surface == Traces.Count)
                {
                    for (int x = 0; x < Traces.Count; x++)
                    {
                        if (MeasurementSettings.PlotRawData) anno.Text += "\nTrace " + (x + 1) + ": " + Traces[x].ThicknessRaw[index].ToString("0.000 000") + " " + MainSettings.UnitsName;
                        else anno.Text += "\nTrace " + (x + 1) + ": " + Traces[x].ThicknessFiltered[index].ToString("0.000 000") + " " + MainSettings.UnitsName;
                    }
                }
                else
                {
                    if (MeasurementSettings.PlotRawData) anno.Text += "\nTrace " + (Surface + 1) + ": " + Traces[Surface].ThicknessRaw[index].ToString("0.000 000") + " " + MainSettings.UnitsName;
                    else anno.Text += "\nTrace " + (Surface + 1) + ": " + Traces[Surface].ThicknessFiltered[index].ToString("0.000 000") + " " + MainSettings.UnitsName;
                }

                anno.Font = new Font("Microsoft Sans Serif", 12);
                anno.AnchorX = 50;
                anno.AnchorY = 14;

                chartMain.Annotations.Clear();
                chartMain.Annotations.Add(anno);

            }
            else chartMain.ChartAreas[0].CursorX.LineColor = Color.Transparent;
        }
        else chartMain.ChartAreas[0].CursorX.LineColor = Color.Transparent;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

}

This index is then used to display the thickness value for each trace displayed on the screen (up to 4 at a time).

When only 1 trace active, this works extremely well. But as soon as 2 or more traces are active, it slows down dramatically.

How can I speed this up, short of increasing the interval?

SRTie4k
  • 105
  • 1
  • 2
  • 8
  • It might be faster to estimate the position in the array (since you know the range of angles, and the approximate increment from element to element) and linear search from there, rather than use Array.BinarySearch. – hatchet - done with SOverflow Jul 01 '14 at 21:07
  • Related question: http://stackoverflow.com/questions/6101820/binary-search-on-keys-of-sortedlistk-v – Justin Killen Jul 01 '14 at 22:26
  • `FindIndexOfAngle` executes only once per `chartMain_MouseMove` call (even if you have 1000 traces). Why have you decided that the problem is in `FindIndexOfAngle` function? – Sergey Krusch Jul 01 '14 at 22:37
  • I haven't decided that the problem is in my search. I figured the search is probably pretty efficient, however firing off all of that every time I move the mouse within 1800 divisions does pose performance problems. – SRTie4k Jul 02 '14 at 11:41
  • 1
    Searching the array seems unlikely to even be noticeable compared to redrawing (parts of) the chart, imho. – Chris Jul 02 '14 at 15:39
  • @Chris Thanks, your comment helped me find the answer, which is posted below. – SRTie4k Jul 02 '14 at 17:23

1 Answers1

2

After doing some searching, I've found why my MouseMove is so slow to update.

I was under the assumption that the slow performance was somehow related to searching through the array, but thanks to Chris from the comments, I instead investigated the drawing aspect and found that I was improperly using a SeriesChartType of Line, when I should be using FastLine.

From MSDN:

The FastLine chart type is a variation of the Line chart that significantly 
reduces the   drawing time of a series that contains a very large number of 
data points. Use this chart in situations where very large data sets are used
and rendering speed is critical.

Some charting features are omitted from the FastLine chart to improve performance. 
The features omitted include control of point level visual attributes, markers, 
data point labels, and shadows.

http://msdn.microsoft.com/en-us/library/dd489249.aspx

SRTie4k
  • 105
  • 1
  • 2
  • 8