Page 1 of 1

Accumulation mode

Posted: Mon May 21, 2012 9:02 am
by 15661458
Hello Steema,

I am drawing an oscilloscope in realtime using FastLine series. I also need a special "accumulation" mode to visualize signal noise by drawing each incoming data set *without* removing any of the previous data already visible. Adding a new series each time my data (8K point set) changes is not an option in a realtime scenario. I tried the Error series, but it does not exactly give me the result I need. Do you have any ideas?

Thanks in advance
Philipp

P.S.
Another small question... How can I convert a mouse client coordinate inside the chart area (not series) to the corresponding chart view position? I need to position the cursor tool to the mouse click position...

Re: Accumulation mode

Posted: Mon May 21, 2012 2:41 pm
by 10050769
Hello Philipp,
I am drawing an oscilloscope in realtime using FastLine series. I also need a special "accumulation" mode to visualize signal noise by drawing each incoming data set *without* removing any of the previous data already visible. Adding a new series each time my data (8K point set) changes is not an option in a realtime scenario. I tried the Error series, but it does not exactly give me the result I need. Do you have any ideas?
Can you please send us a simple code with your data so we can try to find a solution for you? Also, I recommend you take a look in demo project,concretely, in All Features\Welcome !\Functions where there are a examples of function that can helpful for you.
P.S.
Another small question... How can I convert a mouse client coordinate inside the chart area (not series) to the corresponding chart view position? I need to position the cursor tool to the mouse click position...
I recommend you use method CalcPosPoint(int value) of axes that returns the corresponding value of a Screen position.

Thanks,

Re: Accumulation mode

Posted: Mon May 21, 2012 3:57 pm
by 15661458
Hello Sandra,

thanks for your quick reply. I could not find sth. suitable in the demo projects. Here is some code, that should give you the basic idea:

Code: Select all

    // Methods gets called whenever data is available
    public void UpdateChannelData(string seriesName, double[] data)
    {
      var series = _oscilloscopeDataSeries[seriesName];

      if (this.EnableAccumulation)
      {
          // TODO: I want to draw the new set of data while keeping all past series data visualized in the chart.
          // I do not need the complete data and properties of all last series in memory, but just the graphics...
          // Since this method gets called very often (every 30ms) I can not add a new series with approx. 8000 values
          // each time. Is there some way to draw the updated series, without erasing the old series?
      }
      else
      {
        // simple: just reset old values and update the series with incoming data
        series.Delete(0, series.Count);
        series.Add(data);
       }
Your second tip worked great :)

Thanks

Re: Accumulation mode

Posted: Mon May 21, 2012 5:48 pm
by 15661458
I figured out how to do it, but it is rather cumbersome...

Code: Select all


    void OnAfterDraw(object sender, Graphics3D g)
    {
      if (_enableAccumulationMode)
      {
        // 1) render current frame to accumulation buffer
        using (Graphics gfx = Graphics.FromImage(_accumulationBuffer[0]))
        {
          g.BackBuffer.Render(gfx);
        }

        // 2) combine current frame with accumulation buffer
        unsafe
        {
          int width = _accumulationBuffer[0].Width;
          int height = _accumulationBuffer[0].Height;
          var srcData =
            _accumulationBuffer[0].LockBits(Rectangle.FromLTRB(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
          var dstData =
            _accumulationBuffer[1].LockBits(Rectangle.FromLTRB(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

          int* srcPtr = (int*)srcData.Scan0;
          int* dstPtr = (int*)dstData.Scan0;

          HashSet<int> colorLut = new HashSet<int>();
          foreach (var series in _osciDataChannels.Values)
          {
            colorLut.Add(series.Color.ToArgb());
          }

          for (int idx = 0; idx < height * width; idx++, srcPtr++, dstPtr++)
          {
            int srcValue = *srcPtr;
            if (colorLut.Contains(srcValue))
            {
              *dstPtr = srcValue;
            }
          }
          
          _accumulationBuffer[0].UnlockBits(srcData);
          _accumulationBuffer[1].UnlockBits(dstData);
        }

        // 3) draw combined frame on top
        g.Draw(0, 0, _accumulationBuffer[1]);
      }
    }

_accumulationBuffer must be the size of the chart area and updated /reset if scroll or zoom changes or chart size... And yes, this also comes with a performance penalty, but is a lot faster and memory friendly than adding a new series each time
the data changes...

If there is a more elegant / faster way please help me out :)

Thanks
Philipp

Re: Accumulation mode

Posted: Wed May 23, 2012 2:28 pm
by 10050769
Hello Philipp,

Thanks for your code and your solution. I am glad that you have found a solution for your problem. On the other hand, to try to optimize your code would be very helpful for us if you can send your project.

Thanks,