unit DrawBuf;{ Buffer for drawing chromatogram points to screen }
{
  (C) 2000 - 2001 Jindrich Jindrich, Pavel Pisa, PiKRON Ltd.

  Originators of the CHROMuLAN project:

  Jindrich Jindrich - http://www.jindrich.com
                      http://orgchem.natur.cuni.cz/Chromulan/
                      software developer, project coordinator
  Pavel Pisa        - http://cmp.felk.cvut.cz/~pisa
                      embeded software developer
  PiKRON Ltd.       - http://www.pikron.com
                      project initiator, sponsor, instrument developer

  The CHROMuLAN project is distributed under the GNU General Public Licence.
  See file COPYING for details.

  Originators reserve the right to use and publish sources
  under different conditions too. If third party contributors
  do not accept this condition, they can delete this statement
  and only GNU license will apply.
}


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;
    FMaxDataInAcq: integer;
    FIndex: integer;{last calculated index (during GetBuf call) }
  protected
    function GetBuf(AAcqIndex: integer; ADataIndex: integer): TScrBuf;
  public
    constructor Create(ACanvas: TCanvas; const ADisp: TScreenDisp);
    procedure Clear;override;
    destructor Destroy;override;
    procedure BufsClear;
    property Bufs[AAcqIndex: integer; ADataIndex: integer]: TScrBuf read GetBuf; default;
    property CurIndex: integer read FIndex;
  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}
procedure TScrBufs.BufsClear;
var i: integer;
begin
  for i := 0 to Count - 1 do begin
    TScrBuf(Items[i]).Clear;
  end;
end;

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

function TScrBufs.GetBuf(AAcqIndex: integer; ADataIndex: integer): TScrBuf;
begin
  FIndex := AAcqIndex * FMaxDataInAcq + ADataIndex;
  while FIndex >= Count do begin
    Add(TScrBuf.Create(FCanvas, FDisp));
  end;
  GetBuf := TScrBuf(Items[FIndex]);
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.
