unit DrawBuf;

interface
uses
  Classes, Graphics,
  ApexType, UlanType{v1.05}, UlanGlob {/v1.05}, Compareu;

const
  MaxScreenPoints = 800;

type
  TScreenPointInfo = class(TObject)
    X:integer;
    Y1, { first Y value at this X value }
    Y2:integer; { last Y value at this X value }
    {v0.20}
    MinY, { minimal Y value at this X value }
    MaxY: integer; { maximal Y value at this X value }
    {/v0.20}
    constructor Create(AX,AY:integer);
    function Update(AX,AY:integer):boolean;
  end;

  TScreenPoints = class(TList)
    LSPI:TScreenPointInfo;{last inserted one}
    {v1.05}
    LastPoints:array[0..MaxAvgPointCount-1] of TScreenPointInfo;
      { lastly added points (by AddPoint method), used if FFilterType = ftAvg }
    LastPointCount:integer;
      { how many points are in the LastPoints buffer }
    FFilterType:TFilterType;
    FAvgPointCount:longint;
    FFilter1:real;
    {/v1.05}
    constructor Create;
    procedure AddPoint(X,Y:integer);
    procedure Clear;override;
    {v1.05}
    procedure AvgLastPoints;
    {/v1.05}
    property FilterType:TFilterType read FFilterType write FFilterType;
    property AvgPointCount:integer read FAvgPointCount write FAvgPointCount;
    property  Filter1:real read FFilter1 write FFilter1;
  end;

type
  TScrBuf = class(TObject)
  private
    FDisp: TScreenDisp;
    FCanvas: TCanvas;
  public
    Points: TScreenPoints;
    DrawPos: integer;
    LastRec: TScreenPoint;
    constructor Create(ACanvas: TCanvas; const ADisp: TScreenDisp);
    procedure Clear;
    destructor Destroy;override;
    function WasReadyFor(ACanvas: TCanvas; ADisp: TScreenDisp): boolean;
  end;

  TScrBufs = class(TList)
  private
    FCanvas: TCanvas;
    FDisp: TScreenDisp;
  protected
    function GetBuf(Index: integer): TScrBuf;
  public
    constructor Create(ACanvas: TCanvas; const ADisp: TScreenDisp);
    procedure Clear;override;
    destructor Destroy;override;
    property Bufs[Index: integer]: TScrBuf read GetBuf; default;
  end;

implementation

{TScreenPointInfo}
constructor TScreenPointInfo.Create(AX,AY:integer);
begin
  inherited Create;
  X := AX;
  Y1 := AY;
  Y2 := AY;
  {v0.20}
  MinY := AY;
  MaxY := AY;
  {/v0.20}
end;

function TScreenPointInfo.Update(AX,AY:integer):boolean;
begin
  if X = AX then begin
    Update := true;
    {v0.20}
    if AY < MinY then
      MinY := AY
    else if AY > MaxY then
      MaxY := AY;
    Y2 := AY;
    {/v0.20
    if AY > Y2 then
      Y2 := AY
    else if AY < Y1 then
      Y1 := AY;}
  end else
    Update := false;
end;
{/TScreenPointInfo}

{TScreenPoints}
constructor TScreenPoints.Create;
begin
  inherited Create;
  LSPI := nil;
{  FAvgPointCount := ulanglob.AvgPointCount;
  FFilterType := ulanglob.FilterType;
  FFilter1 := ulanglob.Filter1;}
end;

procedure TScreenPoints.AddPoint(X,Y:integer);
{v1.05}
var p:TScreenPointInfo;
{/v1.05}
begin
  if (LSPI = nil) or (not LSPI.Update(X,Y)) then
  begin
    {v1.05}
    p := TScreenPointInfo.Create(X, Y);
    Add(p);
    { filtering done in spectrum.pas - TApexPoints now
    case FFilterType of
      ftNone: ;
      ftAvg: begin
        if LastPointCount < FAvgPointCount then begin
          LastPoints[LastPointCount] := p;
          inc(LastPointCount);
        end else begin
          AvgLastPoints;
        end;
      end;
      ftFilter1: begin
        if LSPI <> nil then begin
          p.Y1 :=  round(LSPI.Y1 * FFilter1 + (1 - FFilter1) * p.Y1);
          p.Y2 :=  round(LSPI.Y2 * FFilter1 + (1 - FFilter1) * p.Y2);
        end;
      end;
    end;
    }
    {/v1.05 Add(TScreenPointInfo.Create(X,Y));}
  end;
  if Count > 0 then
    LSPI := Items[Count - 1];
end;

{v1.05}
procedure TScreenPoints.AvgLastPoints;
var
  i:integer;
  y:integer;
begin
  if LastPointCount = 0 then
    exit;
  y := 0;
  for i := 0 to LastPointCount - 1 do begin
    y := y + LastPoints[i].Y1 + LastPoints[i].Y2;
  end;
  y := y div LastPointCount div 2;
  for i := 0 to LastPointCount - 1 do begin
    LastPoints[i].Y1 := y;
    LastPoints[i].Y2 := y;
  end;
  LastPointCount := 0;
end;
{/v1.05}

procedure TScreenPoints.Clear;
var i:integer;
begin
  if Count > 0 then begin
    for i := 0 to Count - 1 do TObject(Items[i]).Free;
  end;
  LSPI := nil;
  {v1.05}
  LastPointCount := 0;
  {/v1.05}
  inherited Clear;
end;
{/TScreenPoints}

{TScrBuf}
constructor TScrBuf.Create(ACanvas: TCanvas; const ADisp: TScreenDisp);
begin
  inherited Create;
  Clear;
  FCanvas := ACanvas;
  FDisp := ADisp;
end;

procedure TScrBuf.Clear;
begin
  DrawPos := 0;
  LastRec.X := -1;
  Points.Free;
  Points := nil;
end;

destructor TScrBuf.Destroy;
begin
  Clear;
  inherited;
end;

function TScrBuf.WasReadyFor(ACanvas: TCanvas; ADisp: TScreenDisp): boolean;
begin
  Result := true;
  if (Points = nil) or (ACanvas <> FCanvas) or
    (CompareRec(ADisp, FDisp, sizeof(ADisp)) <> 0) then
  begin
    Result := false;
    DrawPos := 0;
    LastRec.X := -1;
    if Points = nil then
      Points := TScreenPoints.Create;
    FCanvas := ACanvas;
    FDisp := ADisp;
  end;
end;
{/TScrBuf}

{/TScrBufs}
constructor TScrBufs.Create(ACanvas: TCanvas; const ADisp: TScreenDisp);
begin
  inherited Create;
  Capacity := MaxDataCountInForm;
  FCanvas := ACanvas;
  FDisp := ADisp;
end;

function TScrBufs.GetBuf(Index: integer): TScrBuf;
begin
  while Index >= Count do begin
    Add(TScrBuf.Create(FCanvas, FDisp));
  end;
  GetBuf := TScrBuf(Items[Index]);
end;

procedure TScrBufs.Clear;
var i:integer;
begin
  for i := 0 to Count - 1 do
    TScrBuf(Items[i]).Free;
  inherited;
end;

destructor TScrBufs.Destroy;
begin
  Clear;
  inherited;
end;
{/TScrBufs}

{
constructor TUserLimitStack .Init;
begin
  if not inherited Init(sizeof(TUserViewLimit), 100, 50)
  then
    Fail;
end;
 }
end.
