Page 1 of 1

TFastLineSeries DrawMarks cause TChart Crash

Posted: Thu Jan 31, 2013 3:18 pm
by 16564094
Hi,
We are using TeeChart2012RADXE2.Build 2012.07.121105
with my Delphi XE2 Update 4

I recently observed some crashs during usage of FastLineSeries. I gave up on making some small example for you.
But I have pin-pointed some problem in your sources I believe:

We have derived from TFastLineSeries ( TOurFastLineSeries = class(TFastLineSeries) )

Here we have made override of DrawMarks.
We do nothing more that just calling inherited DrawMarks. A crash occurs.
And it turns out that when we examine FFirstVisibleIndex from parent class FFirstVisibleIndex

It is -2!!! yes we see "FFirstVisibleIndex = -2"


So for now we made a work around in

TOurFastLineSeries.DrawMarks
begin
...
if "FFirstVisibleIndex < 0 then
"FFirstVisibleIndex := 0;
...
end;

>>> This error will cause the TChart to be non-functional!!! A re-create TChart is needed!! The instance is dead.



If you examine TChartSeries.DrawMarks you will see that St := GetMarkText(t) will produce an error when you put t:= -2

Ok, so where could the the -2 happen?!

The only place we have found where some spooky stuff takes place is in VclTee.Series.pas
procedure TFastLineSeries.CalcFirstLastVisibleIndex;
begin
inherited;

if (not FDrawAll) and (FFirstVisibleIndex = FLastVisibleIndex) and
(FFirstVisibleIndex>-1) then
begin
Dec(FFirstVisibleIndex);
FFirstVisibleIndex:=GetLastYMaxIndex(FFirstVisibleIndex);

>>>> may you need to put a limit on FFirstVisibleIndex, because nothing stops it to become -2... as we have seen happen during debug.
end;

end;

>>>> or in GetLastYMaxIndex may give below -1:


function TFastLineSeries.GetLastYMaxIndex(ValueIndex: Integer): Integer;
var tmpIndex,
pixelXPos : Integer;
begin
tmpIndex:=ValueIndex;
pixelXPos:=GetHorizAxis.CalcXPosValue(XValues.Value[tmpIndex]);

repeat
Dec(tmpIndex);

if tmpIndex > -1 then
pixelXPos := GetHorizAxis.CalcXPosValue(XValues.Value[tmpIndex]);

until ((tmpIndex - 1 = -1) or
(pixelXPos <> GetHorizAxis.CalcXPosValue(XValues.Value[tmpIndex - 1]))
or (tmpIndex < -1)); //TV52015898


>>>>> here you we have seen tmpIndex := -2 ... and maybe it coule even become less... You probably have to put a limit for it?


result:=tmpIndex;
end;



Best regards Christian

Re: TFastLineSeries DrawMarks cause TChart Crash

Posted: Fri Feb 01, 2013 12:26 pm
by yeray
Hello Christian,

I'm trying to reproduce the problem with the code below but it seems to work fine for me here.
Si you see any missing relevant step?

Code: Select all

uses Series;

type
  TOurFastLineSeries = class(TFastLineSeries)
    procedure DrawMarks; override;
  end;

procedure TOurFastLineSeries.DrawMarks;
begin
  inherited;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Chart1.View3D:=false;
  Chart1.AddSeries(TOurFastLineSeries).FillSampleValues();
  Chart1[0].Marks.Visible:=true;
end;

Re: TFastLineSeries DrawMarks cause TChart Crash

Posted: Fri Feb 01, 2013 1:51 pm
by 16564094
Hi,
yes, I understand you want to reproduce it (good engineering philosophy :) )
(But also I hope even if its too difficult to reproduce... you will just fix the code area where we could get the -2 )

I looked in the code to see our series settings, so try also (its like your real-time article)

Series.Marks.Visible := True;
Series.Visible := True;
Series.DrawAllPoints := False;

Series.AutoRepaint := False;
Series.FastPen := True;
Series.LinePen.OwnerCriticalSection := nil;
Series.XValues.Order := loNone;
Series.ShowInLegend := False;
Series.Stairs := True;
Series.XValues.DateTime := True;

Series.Marks.Arrow.Visible := False;
Series.Marks.Callout.Brush.Color := clBlack;
Series.Marks.Callout.Pen.Visible := False;
Series.Marks.Callout.Style := psCircle;
Series.Marks.Callout.Visible := True;
Series.Marks.Callout.Arrow.Visible := False;
Series.Marks.Callout.HorizSize := 3;
Series.Marks.Callout.VertSize := 3;
Series.Marks.Style := smsPercent;
Series.Marks.Transparent := True;
Series.Marks.Clip :=True;


We have observed this happening with XAxis as TDateTimes formatted.

And also we have especially seen it when adding multiple series, say 4 - 6 series.

And then changing the dimensions of the TChart... that will lead to a WndProc based update of the axis. (maybe a timer doing TChart.Invalidate ... will also do it)

Best regards Christian

Re: TFastLineSeries DrawMarks cause TChart Crash

Posted: Mon Feb 04, 2013 11:59 am
by 10050769
Hello Christian,

Thanks for your code, but we continue without reproduce the problem using next code.

Code: Select all

type
  TOurFastLineSeries = class(TFastLineSeries)
    procedure DrawMarks; override;
  end;

procedure TOurFastLineSeries.DrawMarks;
begin
  inherited;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.View3D:=false;
  Chart1.Align := alClient;
  for i := 0 to 6 do
  begin
  Chart1.AddSeries(TOurFastLineSeries).FillSampleValues();
  Chart1[i].Marks.Visible:=true;
   With (Chart1[i] As TOurFastLineSeries) do
    begin
    DrawAllPoints:=False;
    AutoRepaint:=False;
    FastPen := True;
    LinePen.OwnerCriticalSection:=nil;
    Xvalues.Order :=loNone;
    ShowInLegend := False;
    Stairs := True;
    XValues.DateTime :=True;
    Marks.Arrow.Visible := False;
    Marks.Callout.Brush.Color := clBlack;
    Marks.Callout.Pen.Visible := False;
    Marks.Callout.Style := psCircle;
    Marks.Callout.Visible := True;
    Marks.Callout.Arrow.Visible := False;
    Marks.Callout.HorizSize := 3;
    Marks.Callout.VertSize := 3;
    Marks.Style := smsPercent;
    Marks.Transparent := True;
    Marks.Clip :=True;
 end
  end
end;
As you see I have added your suggested code in the Yeray's example and moreover, I have added some modifications.

We need reproduce the problem to solve it to upcoming maintenance releases. For this reason, I would be very grateful if you can provide us a simple example where appears the problem or modify my code because the problem occurs or indicate us, step to step, as we can reproduce the problem.

Thanks,

Re: TFastLineSeries DrawMarks cause TChart Crash

Posted: Thu Feb 07, 2013 2:53 pm
by 16564094
Hello,
Ok I understand.

First we have spend hours to find the error of your sources. we have made a fix for ourselfves.

Now we have further spend 1 hour to try to produce a simple example... unfortunately no luck so far.

We have pin-pointed a very specific section of your sources where we believe that the "FFirstVisibleIndex = -2" can occur.

Unfortunately we on our side also have delivery schedules of our product... so we cannot proceed to spend further time to make simple program for you without charging you for it.

We guess you wont pay for our services, so the only thing we ask is: A reply with sound engineering review of you own sources: Do you see a problem in the sources we pin-pointed or not? Just pure review. If you see some potential problem please take care of it for your next release.

Best regards Christian

Re: TFastLineSeries DrawMarks cause TChart Crash

Posted: Fri Feb 08, 2013 1:21 pm
by yeray
Hi Christian,

I've taken a look at it. But with the information provided this is not easy to track.
As you say, the procedure TFastLineSeries.CalcFirstLastVisibleIndex seems to be the unique place where, having a TFastLineSeries, the FFirstVisibleIndex variable can be modified.

Code: Select all

  if (not FDrawAll) and (FFirstVisibleIndex = FLastVisibleIndex) and
     (FFirstVisibleIndex>-1) then
  begin
     Dec(FFirstVisibleIndex);
     FFirstVisibleIndex:=GetLastYMaxIndex(FFirstVisibleIndex);
  end;
So it seems it can only be GetLastYMaxIndex who could assign a -2 to FFirstVisibleIndex.
Now I've been able to reproduce it. And, if what I've reproduced is the same you were reporting, it doesn't seem to only appear when you inherit from TFastLineSeries and override the DrawMarks method.
Here it is the code I found that ends in a:
Project Project1.exe raised exception class EListError with message 'List index out of bounds (-2)'.
Create a new project with just a chart on the form, use this code and scroll the chart to the right until no point is visible. This ends in the error message above for me.

Code: Select all

procedure TForm1.FormCreate(Sender: TObject);
begin
  Chart1.View3D:=false;
  with Chart1.AddSeries(TFastLineSeries) as TFastLineSeries do
  begin
    FillSampleValues;
    DrawAllPoints:=false;
  end;
  Chart1[0].Marks.Visible:=true;
end;
Is this the error you seem to be experiencing?
A possible fix, pending to verify it doesn't cause any collateral damage, could be to add a condition at TFastLineSeries.CalcFirstLastVisibleIndex:

Code: Select all

  if (not FDrawAll) and (FFirstVisibleIndex = FLastVisibleIndex) and
     (FFirstVisibleIndex>-1) then
  begin
     Dec(FFirstVisibleIndex);
     if (FFirstVisibleIndex>-1) then
       FFirstVisibleIndex:=GetLastYMaxIndex(FFirstVisibleIndex);
  end;

Re: TFastLineSeries DrawMarks cause TChart Crash

Posted: Fri Feb 08, 2013 5:12 pm
by 16564094
Ok as I see you reproduced it, Im happy for that.
I will try to put your proposal after a little vacation (18th feb I will try it).


Best regards Christian

Re: TFastLineSeries DrawMarks cause TChart Crash

Posted: Wed Feb 20, 2013 8:35 am
by 16564094
Hi,
You proposed a possible fix for the FFirstVisibleIndex = -2


if (not FDrawAll) and (FFirstVisibleIndex = FLastVisibleIndex) and
(FFirstVisibleIndex>-1) then
begin
Dec(FFirstVisibleIndex);
if (FFirstVisibleIndex>-1) then
FFirstVisibleIndex:=GetLastYMaxIndex(FFirstVisibleIndex);
end;



As we see it the GetLastYMaxIndex may return -2 still(?)
Just look on the Repeat - Until loop, what will prevent it?

And so this will give risk of FFirstVisibleIndex := -2 again.

1.
How about securing the GetLastYMaxIndex will not return below 0? or maybe below -1?

2.
Or how about making a explicit check:

if (not FDrawAll) and (FFirstVisibleIndex = FLastVisibleIndex) and
(FFirstVisibleIndex>-1) then
begin
Dec(FFirstVisibleIndex);
if (FFirstVisibleIndex>-1) then
FFirstVisibleIndex:=GetLastYMaxIndex(FFirstVisibleIndex);

if FFirstVisibleIndex < 0 then
FFirstVisibleIndex := 0;

end;


Best regards Christian

Re: TFastLineSeries DrawMarks cause TChart Crash

Posted: Mon Feb 25, 2013 3:21 pm
by yeray
Hi Christian,

Excuse us for the delayed reply here.
We actually changed the fix. We have moved the GetLastYMaxIndex function to be nested into TFastLineSeries.CalcFirstLastVisibleIndex, and and this is how it looks like:

Code: Select all

procedure TFastLineSeries.CalcFirstLastVisibleIndex;

  function GetLastYMaxIndex(ValueIndex: Integer): Integer;
  var pixelXPos : Integer;
  begin
    result:=ValueIndex;
    pixelXPos:=GetHorizAxis.CalcXPosValue(XValues.Value[result]);

    while result>0 do
      if GetHorizAxis.CalcXPosValue(XValues.Value[result-1]) <> pixelXPos then
         break
      else
         Dec(result);
  end;

begin
  inherited;

  if (not FDrawAll) and (FFirstVisibleIndex = FLastVisibleIndex) then
      if FFirstVisibleIndex>0 then
         FFirstVisibleIndex:=GetLastYMaxIndex(FFirstVisibleIndex-1)
      else
         FFirstVisibleIndex:=-1;
end;

Re: TFastLineSeries DrawMarks cause TChart Crash

Posted: Tue Feb 26, 2013 8:26 am
by 16564094
Ok great!

I look forward to the maintenance release. Is there an approx date for your next release?

Best regards Christian

Re: TFastLineSeries DrawMarks cause TChart Crash

Posted: Tue Feb 26, 2013 10:54 am
by yeray
Hi Christian,
pch-chj wrote:Is there an approx date for your next release?
We are working on it but I'm afraid I can't tell you a date for it to be published.