TAChart: Add TChartSourceBuffer utility class

git-svn-id: trunk@28800 -
This commit is contained in:
ask 2010-12-22 10:31:17 +00:00
parent 7cc2d96db6
commit b669510279
3 changed files with 130 additions and 23 deletions

View File

@ -25,6 +25,7 @@ uses
Classes, Types, TAChartUtils;
type
EBufferError = class(EChartError);
EEditableSourceRequired = class(EChartError);
EYCountError = class(EChartError);
@ -87,6 +88,26 @@ type
property YCount: Cardinal read FYCount write SetYCount default 1;
end;
{ TChartSourceBuffer }
TChartSourceBuffer = class
private
FBuf: array of TChartDataItem;
FCount: Cardinal;
FStart: Cardinal;
FSum: TChartDataItem;
function GetCapacity: Cardinal; inline;
procedure Put(AIndex: Integer; const AItem: TChartDataItem);
procedure Remove(AIndex: Integer);
procedure SetCapacity(AValue: Cardinal); inline;
public
procedure AddFirst(const AItem: TChartDataItem);
procedure AddLast(const AItem: TChartDataItem);
procedure Clear; inline;
procedure GetSum(var AItem: TChartDataItem);
property Capacity: Cardinal read GetCapacity write SetCapacity;
end;
procedure SetDataItemDefaults(var AItem: TChartDataItem);
implementation
@ -106,6 +127,89 @@ begin
AItem.YList[i] := 0;
end;
{ TChartSourceBuffer }
procedure TChartSourceBuffer.AddFirst(const AItem: TChartDataItem);
begin
if Capacity = 0 then
raise EBufferError.Create('');
FStart := (FStart + Cardinal(High(FBuf))) mod Capacity;
if FCount = Capacity then
Remove(FStart)
else
FCount += 1;
Put(FStart, AItem);
end;
procedure TChartSourceBuffer.AddLast(const AItem: TChartDataItem);
begin
if Capacity = 0 then
raise EBufferError.Create('');
if FCount = Capacity then begin
Remove(FStart);
Put(FStart, AItem);
FStart += 1;
end
else begin
Put((FStart + FCount) mod Capacity, AItem);
FCount += 1;
end;
end;
procedure TChartSourceBuffer.Clear;
begin
FCount := 0;
FSum.Y := 0;
FSum.YList := nil;
end;
function TChartSourceBuffer.GetCapacity: Cardinal;
begin
Result := Length(FBuf);
end;
procedure TChartSourceBuffer.GetSum(var AItem: TChartDataItem);
begin
if FCount = 0 then
raise EBufferError.Create('Empty');
AItem.Y := FSum.Y;
AItem.YList := Copy(FSum.YList);
end;
procedure TChartSourceBuffer.Put(AIndex: Integer; const AItem: TChartDataItem);
var
i, oldLen: Integer;
begin
FBuf[AIndex] := AItem;
with FSum do begin
Y += AItem.Y;
oldLen := Length(YList);
SetLength(YList, Max(Length(AItem.YList), oldLen));
for i := oldLen to High(YList) do
YList[i] := 0;
for i := 0 to Min(High(YList), High(AItem.YList)) do
YList[i] += AItem.YList[i];
end;
end;
procedure TChartSourceBuffer.Remove(AIndex: Integer);
var
i: Integer;
begin
with FBuf[AIndex] do begin
FSum.Y -= Y;
for i := 0 to Min(High(FSum.YList), High(YList)) do
FSum.YList[i] -= YList[i];
end;
end;
procedure TChartSourceBuffer.SetCapacity(AValue: Cardinal);
begin
if AValue = Capacity then exit;
SetLength(FBuf, AValue);
Clear;
end;
{ TCustomChartSource }
procedure TCustomChartSource.AfterDraw;

View File

@ -205,7 +205,7 @@ type
private
FAccumulationMethod: TChartAccumulationMethod;
FAccumulationRange: Integer;
FHistory: array of TChartDataItem;
FHistory: TChartSourceBuffer;
FIndex: Integer;
FItem: TChartDataItem;
FListener: TListener;
@ -218,7 +218,7 @@ type
procedure CalcAccumulation(AIndex: Integer);
procedure CalcPercentage;
procedure Changed(ASender: TObject); inline;
procedure ExtractItem(var AItem: TChartDataItem; AIndex: Integer);
procedure ExtractItem(out AItem: TChartDataItem; AIndex: Integer);
procedure SetAccumulationMethod(AValue: TChartAccumulationMethod);
procedure SetAccumulationRange(AValue: Integer);
procedure SetOrigin(AValue: TCustomChartSource);
@ -999,28 +999,25 @@ end;
procedure TCalculatedChartSource.CalcAccumulation(AIndex: Integer);
var
i, j: Integer;
i: Integer;
begin
SetLength(FHistory, AccumulationRange);
FHistory.Capacity := AccumulationRange;
if FIndex = AIndex - 1 then begin
for i := High(FHistory) downto 1 do
FHistory[i] := FHistory[i - 1];
ExtractItem(FHistory[0], AIndex);
ExtractItem(FItem, AIndex);
FHistory.AddLast(FItem);
end
else
for i := 0 to Min(High(FHistory), AIndex) do
ExtractItem(FHistory[i], AIndex - i);
SetDataItemDefaults(FItem);
for i := 0 to Min(High(FHistory), AIndex) do begin
FItem.Y += FHistory[i].Y;
for j := 0 to High(FItem.YList) do
FItem.YList[j] += FHistory[i].YList[j];
else begin
FHistory.Clear;
for i := Max(AIndex - AccumulationRange + 1, 0) to AIndex do begin
ExtractItem(FItem, i);
FHistory.AddLast(FItem);
end;
end;
FItem.X := FHistory[0].X;
FHistory.GetSum(FItem);
if AccumulationMethod = camAverage then begin
FItem.Y /= Min(AccumulationRange, AIndex + 1);
for j := 0 to High(FItem.YList) do
FItem.YList[j] /= Min(AccumulationRange, AIndex + 1);
for i := 0 to High(FItem.YList) do
FItem.YList[i] /= Min(AccumulationRange, AIndex + 1);
end;
end;
@ -1051,17 +1048,19 @@ constructor TCalculatedChartSource.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FIndex := -1;
FHistory := TChartSourceBuffer.Create;
FListener := TListener.Create(@FOrigin, @Changed);
end;
destructor TCalculatedChartSource.Destroy;
begin
FreeAndNil(FHistory);
FreeAndNil(FListener);
inherited Destroy;
end;
procedure TCalculatedChartSource.ExtractItem(
var AItem: TChartDataItem; AIndex: Integer);
out AItem: TChartDataItem; AIndex: Integer);
var
t: TDoubleDynArray;
i: Integer;

View File

@ -74,11 +74,14 @@ begin
FSource.AccumulationMethod := camSum;
FSource.AccumulationRange := 2;
AssertEquals(3, FSource.YCount);
AssertEquals(1, FSource[0]^.X);
AssertEquals(102, FSource[0]^.Y);
AssertEquals(2, FSource[1]^.X);
AssertEquals(102 + 202, FSource[1]^.Y);
AssertEquals(202 + 302, FSource[2]^.Y);
FSource.AccumulationMethod := camAverage;
AssertEquals((202 + 302) / 2, FSource[2]^.Y);
AssertEquals((2002 + 2102) / 2, FSource[20]^.Y);
AssertEquals(1, FSource[0]^.X);
AssertEquals(102, FSource[0]^.Y);
AssertEquals((102 + 202) / 2, FSource[1]^.Y);
end;
@ -114,15 +117,16 @@ begin
end;
procedure TCalculatedSourceTest.SetUp;
var
i: Integer;
begin
inherited SetUp;
FOrigin := TListChartSource.Create(nil);
FSource := TCalculatedChartSource.Create(nil);
FSource.Origin := FOrigin;
FOrigin.YCount := 3;
FOrigin.SetYList(FOrigin.Add(1, 102), [103, 104]);
FOrigin.SetYList(FOrigin.Add(2, 202), [203, 204]);
FOrigin.SetYList(FOrigin.Add(3, 302), [303, 304]);
for i := 1 to 100 do
FOrigin.SetYList(FOrigin.Add(i, i * 100 + 2), [i * 100 + 3, i * 100 + 4]);
end;
procedure TCalculatedSourceTest.TearDown;