Page 1 of 1

Range Checking Error in YPosValueCheck

Posted: Wed Feb 15, 2012 4:27 pm
by 16559464
First I have TeeChart VCL 9.03 and I am working with Delphi XE developing a Win32 application.

In my application I have implemented a strip chart recorder using a TLineSeries to display data that is generated asynchronously. Operators need to be able to zoom in on the results. I have observed in cases where an operator zooms the chart when there is zero or perhaps only a single point in a chart this can result in a range checking error. I can disable zoom until there is data in the chart, but completely disabling zooming is out of the question.

The root cause of the problem appears to be in Module TeEngine.Pas, procedure TChartAxis.InternalCalcRange()

The following lines allows special handling for empty charts (which may cause axis scaling problems):
IRangeZero:=IRange=0;
if IRangeZero then IAxisSizeRange:=0
else IAxisSizeRange:=IAxisSize/IRange;

However if IRange = MinAxisRange (Double = 0.0000000001), which seems to be common enough when zooming with one data point in the chart, this will result in a VERY large IAxisSizeRange value that leads to a range check error in TChartAxis.YPosValueCheck() where it tries to convert a huge floating point value to the function result, which is a 32-bit integer.

tmp:=(Value-IMinimum)*IAxisSizeRange;
...
if FInverted then result:=IStartPos+Round(tmp)
else result:=IEndPos-Round(tmp);

I usually observer tmp values of around 200 billlion just before the range check error issues from the Round() function.

To try and work around this problem, I have made the following change to TChartAxis.InternalCalcRange

IRangeZero:=IRange=0;
To
IRangeZero:=ABS(IRange) <= MinAxisRange*IAxisSize;

This seems to work, but if anyone knows a reason why this is a bad solution to this problem, I'd really appreciate that insight before I ship this product.

Re: Range Checking Error in YPosValueCheck

Posted: Mon Feb 20, 2012 10:22 am
by narcis
Hello,

Could you please attach a simple example project we can run "as-is" and let us know the exact instructions we should perform to reproduce the problem here?

Thanks in advance.

Re: Range Checking Error in YPosValueCheck

Posted: Thu Feb 23, 2012 2:45 pm
by 16559464
I have created and attached the simplest possible project to illustrate the issue. The full project source is included, but the smallest possible executable cannot be zipped down to less than the 512Kb limit allows on this forum.

To rebuild the project:
1) Obviously range checking must be enabled.
2) The TeeChart source must be on the build search path.

In the sample, I'm using a timer to generate data asynchronously. Data is generated every 2.5 seconds to allow lots of time for zooming between data arrival.

To generate the error, click the Start button, wait for a single point to appear in the chart (the left axis will change because it is automatic), then zoom in on a small region in the middle of the chart somewhere. Then you'll get the range checking error.

If you need the executable I can put it on our ftp site for you to get.

Re: Range Checking Error in YPosValueCheck

Posted: Tue Feb 28, 2012 9:55 am
by yeray
Hi,

I'm trying to reproduce it with your application but I can't. It seems to compile and run fine for me here in XE with TeeChart v2011.04. I've checked it has "Range checking" active and I'm zooming in (drawing a zoom rectangle as little as I can, and zooming in several times) once a first point (and also with a second, a third,...) has been added to the series.

If I understood well, the following simple example should be doing something similar, I've even added two SetMinMax calls, to perform the zoom automatically, but the error doesn't appear.

Code: Select all

uses Series;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Chart1.View3D:=false;
  Chart1.AddSeries(TLineSeries);
  Chart1[0].AddXY(10, 50);
  Chart1[0].AddXY(15, 51);

  Chart1.Axes.Bottom.SetMinMax(0, 50);
  Chart1.Axes.Left.SetMinMax(50, 50.00005);
end;

Re: Range Checking Error in YPosValueCheck

Posted: Wed Feb 29, 2012 3:07 pm
by 16559464
I have version 9.03 (which I believe is the same as 2011.03 ?)

I've changed the timer event handler code to disable the timer in my example after generating a single point, to more easily generate the condition that allows the issue to arise.

Code: Select all

procedure TForm1.Timer1Timer(Sender: TObject);
  begin
  if Assigned(serStrip.ParentChart) then
    serStrip.ParentChart.AutoRepaint := False;
  serStrip.YValue[iChartPointCount] := Random(200);
  serStrip.ValueColor[iChartPointCount] := serStrip.SeriesColor;
  if Assigned(serStrip.ParentChart) then
    serStrip.ParentChart.AutoRepaint := True;
  if not serStrip.ParentChart.Zoom.Active then
    begin
    serStrip.ParentChart.Invalidate;
    PostMessage(serStrip.ParentChart.Handle, WM_PAINT, 0, 0);
    end;
  Timer1.Enabled := False;
  btnStart.Enabled := True;
  btnStop.Enabled  := False;
  end;
Your example is missing a key element which (I believe) is causing the issue. My understanding is that the primary reason the scaling issue comes up is that there is in fact only a single point in the chart, and because axis autoscaling is enabled. I've attached a screenshot showing what the chart looks like just before the Range Error happens (I changed the colors to enhance contrast). As you can see the left axis has no discernible scaling cues because it has only a single point in the chart, and I believe zooming in when in this state is what is causing the problem.

TeEngine.SetMinMax() has the following code which prevents you from setting the axis scale in a range that will illustrate the problem.

Code: Select all

  if (FMaximumValue-FMinimumValue)<MinAxisRange then
     InternalSetMaximum(FMinimumValue+MinAxisRange);
So you can't force the issue using SetMinMax().

Re: Range Checking Error in YPosValueCheck

Posted: Fri Mar 02, 2012 4:17 pm
by yeray
Hi,

I could reproduce it now. We'll investigate it further and tell you what we find asap.

Re: Range Checking Error in YPosValueCheck

Posted: Wed Mar 07, 2012 11:18 am
by yeray
Hi,

This is quite confusing.
The first time I tried this I couldn't reproduce the problem neither in Delphi 7 nor in XE. Then, I asked NarcĂ­s to give it a try and he could reproduce it. Then, suddenly, I could reproduce it too in the same environment where I couldn't before. Now, I'm not able to reproduce it any more.
Could you please give a try to the actual version v2011.04 (yes, aka v9.04)?

Re: Range Checking Error in YPosValueCheck

Posted: Wed Mar 07, 2012 2:40 pm
by 16559464
I installed 9.04 (2001.04) this morning, and recompiled the application. It exhibits the same issue. I inspected the relevant code in InternalCalcRange() and it's exactly the same, so I would expect the same result.

I compiled a version with Eurekalog included in the project and the stack trace to the point of the exception is listed below. I don't know if that helps you or not, but you can see exactly where it fails, and the path it takes to get there (unfortunately calls not directly on the path to the exception do not show up).

Code: Select all

Call Stack Information:
-------------------------------------------------------------------------------------
|Address |Module        |Unit          |Class           |Procedure/Method |Line     |
-------------------------------------------------------------------------------------
|Running Thread: ID=5316; Priority=0; Class=; [Main]                                |
|-----------------------------------------------------------------------------------|
|005764E4|ChartRange.exe|TeEngine.pas  |TChartAxis      |YPosValueCheck   |4563[19] |
|005790E9|ChartRange.exe|TeEngine.pas  |                |InternalDrawLabel|5520[1]  |
|005790B4|ChartRange.exe|TeEngine.pas  |                |InternalDrawLabel|5519[0]  |
|005797DC|ChartRange.exe|TeEngine.pas  |                |DoDefaultLabels  |5660[37] |
|005794EC|ChartRange.exe|TeEngine.pas  |                |DoDefaultLabels  |5623[0]  |
|00579938|ChartRange.exe|TeEngine.pas  |                |DoNotCustomLabels|5702[2]  |
|00579904|ChartRange.exe|TeEngine.pas  |                |DoNotCustomLabels|5700[0]  |
|0057A00A|ChartRange.exe|TeEngine.pas  |                |DoDrawLabels     |5847[39] |
|00579DF0|ChartRange.exe|TeEngine.pas  |                |DoDrawLabels     |5808[0]  |
|0057A13C|ChartRange.exe|TeEngine.pas  |TChartAxis      |Draw             |5877[9]  |
|0057A0B8|ChartRange.exe|TeEngine.pas  |TChartAxis      |Draw             |5868[0]  |
|0058A288|ChartRange.exe|TeEngine.pas  |                |DrawAllAxis      |13575[14]|
|0058A1C8|ChartRange.exe|TeEngine.pas  |                |DrawAllAxis      |13561[0] |
|0058AECF|ChartRange.exe|TeEngine.pas  |TCustomAxisPanel|DrawAxesSeries   |13827[7] |
|0058AE9C|ChartRange.exe|TeEngine.pas  |TCustomAxisPanel|DrawAxesSeries   |13820[0] |
|0058A14A|ChartRange.exe|TeEngine.pas  |TCustomAxisPanel|InternalDraw     |13537[47]|
|0055E7A6|ChartRange.exe|TeeProcs.pas  |TCustomTeePanel |Draw             |1862[22] |
|0055E3DB|ChartRange.exe|TeeProcs.pas  |TCustomTeePanel |Draw             |1770[19] |
|0055E3B4|ChartRange.exe|TeeProcs.pas  |TCustomTeePanel |Draw             |1751[0]  |
|0055E823|ChartRange.exe|TeeProcs.pas  |TCustomTeePanel |Paint            |1900[11] |
|0058B6FD|ChartRange.exe|TeEngine.pas  |TCustomAxisPanel|CheckMouseSeries |14117[6] |
|0059B597|ChartRange.exe|Chart.pas     |TCustomChart    |MouseMove        |3913[93] |
|0059B5B2|ChartRange.exe|Chart.pas     |TCustomChart    |MouseMove        |3914[94] |
|760E7252|USER32.dll    |              |                |GetPropW         |         |
|760E7227|USER32.dll    |              |                |GetPropW         |         |
|760E7885|USER32.dll    |              |                |DispatchMessageW |         |
|760E787B|USER32.dll    |              |                |DispatchMessageW |         |
|005B3231|ChartRange.exe|ChartRange.dpr|                |                 |14[4]    |

Re: Range Checking Error in YPosValueCheck

Posted: Tue Mar 13, 2012 12:20 pm
by yeray
Hi,

Well, I've added it to the wish list to be investigated further and apply your suggestion (or another similar) if we find it doesn't break other compatibilities (TV52016082).