{ Copyright (C) 2006 by Shleps
  This library is a part of ChaosWarehouse project.

  It is free software; you can redistribute it and/or modify it
  under the terms of the GNU Library General Public License v2
                                  
  This program is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  for more details.

  Usage example:
// creation  
  Drawer:=TDrawer.Create(WCanvas);
//this must be used after change of view origin, scale and angle 
  Drawer.RecalcMatrix;
// conversion from screen to world coords  
  Drawer.StoW(X-(Drawer.Wx Div 2),(Drawer.Wy Div 2)-Y,Xw,Yw);
// conversion from world to screen and drawing directly
  Drawer.WtoS(Xw0,Yw0,X0,Y0);
  WCanvas.MoveTo(X0+(Drawer.Wx Div 2),(Drawer.Wy Div 2)-Y0);
//drawing using commands
  Drawer.ExecCommand('SetWidth 1',Acc);
applicable commands are
01  Set      var=value
02  Unset    var
04  SetWidth       x
03  SetColor       n
05  SetBGColor     n
06  SetFont        font,size,color,bius
19  SetScaledFont  font,height,scale,color,bius
10  MoveTo         x,y
09  LineTo         x,y
11  Rect           x1,y1,x2,y2
12  RoundRect      x1,y1,x2,y2
08  Ellipse        x1,y1,x2,y2
13  Circle         x,y,r
14  TextOut        x,y,text
15  Bmp            x1,y1,x2,y2,cachename
16  SubPicture     x,y,angle,scale,filename
17  SetTextStyle   opaque
18  SetPenStyle    psDot
20  UnScaled       box1,pixelsize
21  TextRect       x1,y1,x2,y2,text
07  floodfill      x,y,color

}

unit Tpg; 

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, ShlepsUtils, Graphics, GraphType, Dispatcher, Math;

type


  TAcceleratedCommand=Array[1..5] Of Extended;
  TAccObject=Class
    AcceleratedCommand:TAcceleratedCommand;
  end;

  TPoint2D=Array[1..3] of Extended;
  TMatrix2D=Array[1..3,1..3] Of Extended;
  TShell=Record
    X1,X2,Y1,Y2:Extended;
  End;

  TGraphCacheItem = Class(TObject)
    Src:String;
    LinkCount:Longint;
    Typ:String;
    PixData:TBitmap;
    TxtData:TStringList;
    VectData:TStringList;
    Constructor Create(s,T:String);
    Destructor Destroy;
  End;

  TDrawer = Class(TObject)
    Updated:Boolean;
    AxisMode:Longint;     // 0 - math mote (0-center, 0Y - up), 1 - GUI mode (0 left-top corner, 0Y - down)
    ViewScale:Extended;   // Scale measured in meters per pixel
    ViewX,ViewY:Extended; // Origin of view (meters)
    ViewAngle:Extended;   // -azimuth of view, north by default
    TransM,RTransM:TMatrix2D;
    Canvas:TCanvas;
    Wx,Wy:Longint; // canvas size in pixels used for flip vertical axis
    PrintMultiplier:Longint; // multiply pen width for printing
    PenColor:TColor;
    EnforcedPenColor:TColor;
    BrushColor:TColor;
    EnforcedBrushColor:TColor;
    EnforcedPenStyle:TPenStyle;
    PenWidth:Longint;
    VarList:TStringList;  // list of pairs variable=value
    Resolver:TStringList; // convertor of names to displaylists
   // GraphCache:TStringList; // list of graphcache items
    Constructor Create(wCanvas:TCanvas);
    Destructor Destroy;
    Procedure RecalcMatrix; //
    Procedure StoW(Xs,Ys:Longint;Var Xw,Yw:Extended); //convert screen to world coords
    Procedure WtoS(Var Xw,Yw:Extended;Var Xs,Ys:Longint); //convert world to screen coords
    Procedure ExecCommand(Command:string;AcceleratedCommand:TAcceleratedCommand);
    Function ParseLine(Data:String):String;
  End;

  Const ZeroAcc:  TAcceleratedCommand=(0,0,0,0,0);
        E:  TMatrix2D=((1,0,0),(0,1,0),(0,0,1));
        Var GOPS:Longint;

Var GraphCache:TStringList;

Function GenShift(dX,dY:Extended):TMatrix2D;
Function GenScale(x,y:Extended;SX,SY:Extended):TMatrix2D;
Function GenRotate(X,Y,A:Extended):TMatrix2D;
Function MulMat2D(M1,M2:TMatrix2D):TMatrix2D;
Function MulPoint2D(P:TPoint2D;M:TMatrix2D):TPoint2D;
Function PointInRect(x,y:Longint;Rect:TRect):Boolean;
Function PointInWRect(x,y:Extended;X1,Y1,X2,Y2:Extended):Boolean;
Function AccelerateCommand(Command:String):TAcceleratedCommand;
Procedure UpdateCacheItem(Name:String);


implementation

Uses CADEngine, Unit1;

Function PointInRect(x,y:Longint;Rect:TRect):Boolean;
Begin
  Result:=(Rect.Left<=x)And(x<=Rect.Right)And(Rect.Top<=y)And(y<=Rect.Bottom);
end;

Function PointInWRect(x,y:Extended;X1,Y1,X2,Y2:Extended):Boolean;
Var Xmin,XMax,Ymin,Ymax:Extended;
Begin
  If X1<=X2 Then Begin Xmin:=X1;Xmax:=X2;end
  Else Begin Xmin:=X2;Xmax:=X1;End;
  If Y1<=Y2 Then Begin Ymin:=Y1;Ymax:=Y2;end
  Else Begin Ymin:=Y2;Ymax:=Y1;End;
  Result:=(Xmin<=x)And(x<=Xmax)And(Ymin<=y)And(y<=Ymax);
end;

Function MulMat2D(M1,M2:TMatrix2D):TMatrix2D;
Var R:TMatrix2D;I,J,K:Longint;
Begin
  For I:=1 To 3 Do
    For J:=1 To 3 Do
      R[I,J]:=0;
  For I:=1 To 3 Do Begin
    For J:=1 To 3 Do Begin
      For K:=1 To 3 Do Begin
        R[I,J]:=R[I,J]+M1[I,K]*M2[K,J];
      End;
    End;
  End;
  Result:=R;
End;

Function MulPoint2D(P:TPoint2D;M:TMatrix2D):TPoint2D;
Var R:TPoint2D;I,J,K:Longint;
Begin
  For I:=1 To 3 Do
      R[I]:=0;
  For J:=1 To 3 Do Begin
    For K:=1 To 3 Do Begin
      R[J]:=R[J]+P[k]*M[K,J];
    End;
  End;
  Result:=R;
End;

Function GenShift(dX,dY:Extended):TMatrix2D;
Var M:TMatrix2D;
Begin  M[1,1]:=1;M[1,2]:=0;M[1,3]:=0;
       M[2,1]:=0;M[2,2]:=1;M[2,3]:=0;
       M[3,1]:=dx;M[3,2]:=dy;M[3,3]:=1;
       Result:=M;
End;

Function GenScale(x,y:Extended;SX,SY:Extended):TMatrix2D;
Var M:TMatrix2D;
Begin  M[1,1]:=SX;M[1,2]:=0;M[1,3]:=0;
       M[2,1]:=0;M[2,2]:=SY;M[2,3]:=0;
       M[3,1]:=(1-SX)*x;M[3,2]:=(1-SY)*y;M[3,3]:=1;
       Result:=M;
End;

Function GenRotate(X,Y,A:Extended):TMatrix2D;
Var M:TMatrix2D;S,C:Extended;
Begin S:=Sin(A);C:=Cos(A);
      M[1,1]:=C;M[1,2]:=S;M[1,3]:=0;
      M[2,1]:=-S;M[2,2]:=C;M[2,3]:=0;
      M[3,1]:=X*(1-C)+Y*S;M[3,2]:=Y*(1-C)-X*S;M[3,3]:=1;
      Result:=M;
End;

Constructor TGraphCacheItem.Create(S,T:String);
Begin
  Src:=S;
  Typ:=T;
  LinkCount:=0;
  Case Typ Of
  'txt': Begin TxtData:=TStringList.Create;PixData:=Nil;VectData:=Nil;End;
  'pix': Begin TxtData:=Nil;PixData:=TBitmap.Create;VectData:=Nil;End;
  'vect': Begin TxtData:=Nil;PixData:=Nil;VectData:=TStringList.Create;End;
  End;
  GraphCache.AddObject(Src,Self);
End;

Destructor TGraphCacheItem.Destroy;
Var I:Longint;
Begin
  I:=GraphCache.IndexOf(Src);
  If I>=0 Then GraphCache.Delete(I);
  Case Typ Of
  'txt': Begin TxtData.Free;PixData:=Nil;VectData:=Nil;End;
  'pix': Begin TxtData:=Nil;PixData.Free;VectData:=Nil;End;
  'vect': Begin TxtData:=Nil;PixData:=Nil;VectData.Free;End;
  End;
End;

Procedure UpdateCacheItem(Name:String);
Var CacheIndex:Longint;
    CacheItem:TGraphCacheItem;
    BM:TBitmap;Picture:TPicture;FBuf:TStringList;
Begin
  If Name='' Then Exit;
  CacheIndex:=GraphCache.IndexOf(Name);
  If CacheIndex<0 Then Exit;
  CacheItem:=GraphCache.Objects[CacheIndex] As TGraphCacheItem;
  Case CacheItem.Typ Of
  'pix': Begin
             CacheItem.PixData.Free;
             BM:=TBitmap.Create;
             Picture:=TPicture.Create;
             LoadImageFromURL(ExpandURL(Name),Picture);
             Bm.Assign(Picture.Graphic);
             Picture.Free;
             CacheItem:=TGraphCacheItem.Create(Name,'pix');
             CacheItem.PixData:=BM;
         End;
  'txt','vect': Begin
                  FBuf:=CacheItem.TxtData;
                  LoadTextFromURL(ExpandURL(Name),FBuf);
                End;
  End;
End;
Constructor TDrawer.Create(wCanvas:TCanvas);
Var Sm,Rm,Scm,tmpm:TMatrix2D;
Begin
  AxisMode:=0;
  Canvas:=WCanvas;
  Wx:=Canvas.Width;
  Wy:=Canvas.Height;  
  VarList:=TStringList.Create;
//  GraphCache:=TStringList.Create;
  ViewX:=0;ViewY:=0;ViewScale:=1;ViewAngle:=0;
  RecalcMatrix;
End;
Destructor TDrawer.Destroy;
Begin
  VarList.Clear;
  VarList.Free;
  Inherited Destroy;
End;

Procedure TDrawer.RecalcMatrix;
Var Sm,Rm,Scm,tmpm:TMatrix2D;
Begin
  Sm:=GenShift(-viewx,-viewy);
  Rm:=GenRotate(0,0,ViewAngle);
  Scm:=GenScale(0,0,1/ViewScale,1/ViewScale);
  tmpm:=MulMat2D(Sm,Rm);
  TransM:=MulMat2D(Tmpm,Scm);
  Sm:=GenShift(viewx,+viewy);
  Rm:=GenRotate(0,0,-ViewAngle);
  Scm:=GenScale(0,0,ViewScale,ViewScale);
  tmpm:=MulMat2D(Scm,Rm);
  RTransM:=MulMat2D(Tmpm,Sm);
End;

Procedure TDrawer.StoW(Xs,Ys:Longint;Var Xw,Yw:Extended);
Var Xc,Yc:Extended;
    p1,p2:TPoint2D;
Begin
{  Xc:=Xs;
  Yc:=Ys;
  Xw:=(Xc*CosA+Yc*SinA)*ViewScale+ViewX;
  Yw:=(-Xc*SinA+Yc*CosA)*ViewScale+ViewY;}
  If AxisMode=0 Then Begin
    Xc:=Xs-(Self.Wx Div 2);
    Yc:=(Self.Wy Div 2)-Ys;
  End Else Begin
    Xc:=Xs;Yc:=Ys;
  End;
  P1[1]:=Xc;P1[2]:=Yc;P1[3]:=1;
  P2:=MulPoint2D(P1,RTransM);
  Xw:=p2[1];Yw:=p2[2];
End;

Procedure TDrawer.WtoS(Var Xw,Yw:Extended;Var Xs,Ys:Longint);
Var Xc,Yc:Extended;
   p1,p2:TPoint2D;
Begin
  P1[1]:=Xw;P1[2]:=Yw;P1[3]:=1;
  P2:=MulPoint2D(P1,TransM);
  Xs:=Round(p2[1]);Ys:=Round(p2[2]);
//  Xs:=Trunc(p2[1]);Ys:=Trunc(p2[2]);
  If AxisMode=0 Then Begin
    Xs:=Xs+(Self.Wx Div 2);
    Ys:=(Self.Wy Div 2)-Ys;
  End;
End;

Function TDrawer.ParseLine(Data:String):String;  // replaces %template% with value from varlist
Var K,I,J,I1,I2,N,StartOfAlias,EndOfAlias,idx:Longint;Bufer:String;
    Alias:String;IsAlias:Boolean;
Begin
      Bufer:=Data;
      IsAlias:=False;
      Alias:='';
      I:=1;
      While I<=Length(Bufer) Do Begin // while instead of for because possible decrease of length
        If Bufer[I]='%' Then Begin
          IsAlias:=True; StartOfAlias:=I; Alias:='';
          For J:=I+1 To Length(Bufer) Do Begin
            If Bufer[J]='%' Then Begin
              IsAlias:=False;
              EndOfAlias:=J;
              idx:=VarList.IndexOfName(Alias);
              If idx<0 Then Begin // no such alias in vocabulary
                Break; //out of J-cycle, continue to search another %...%
              End Else Begin
                Delete(Bufer,StartOfAlias,EndOfAlias-StartOfAlias+1);
                Insert(VarList.ValueFromIndex[idx],Bufer,StartOfAlias);
                Break;
              End;
            End Else
              Alias:=Alias+Bufer[J];
          End;
        End Else Begin
        End;
        Inc(I);
      End;
      Result:=Bufer;
end;

Function Cmd2Acc(Cmd:String):Extended;
Begin
  Case LowerCase(Cmd) Of
  'set': Result:=1;
  'unset': Result:=2;
  'setcolor': Result:=3;
  'setwidth': Result:=4;
  'setbgcolor': Result:=5;
  'setfont': Result:=6;
  'floodfill': Result:=7;
  'ellipse': Result:=8;
  'lineto': Result:=9;
  'moveto': Result:=10;
  'rect': Result:=11;
  'roundrect': Result:=12;
  'circle': Result:=13;
  'textout': Result:=14;
  'bmp': Result:=15;
  'subpicture': Result:=16;
  'settextstyle': Result:=17;
  'setpenstyle': Result:=18;
  'setscaledfont': Result:=19;
  'unscaled': Result:=20;
  'textrect': Result:=21;
  Else Result:=0;
  end;
end;


Function AccelerateCommand(Command:String):TAcceleratedCommand;
Var Cmd,Buf,ParsedBuf,fname:String;
    FBuf:TStringList;
    Color:TColor;
    Xs,Ys,Rs:Longint;xws,yws,Rws:String;
    X2s,Y2s:Longint;x2ws,y2ws:String;
    DisplayList:TStringList;
    Angle:Extended;AngleS:String;
    PicScale:Extended;PicScaleS:String;
    Xw,Yw,Rw:Extended; PixR:Longint;
    X2w,Y2w:Extended;
    R1,R2:TRect;BM:TBitmap;
    SubDrawer:TDrawer;
    I:Longint;Sm,Rm,Scm,tmpm:TMatrix2D;
    FontFace,FontSize,FontColor,BIUS:String;
    Acc:TAcceleratedCommand;
Begin
  Buf:=(Command);
  Cmd:=GetNextToken(Buf,ParsedBuf,' ');
  Buf:=ParsedBuf;
  Case LowerCase(Cmd) Of
  'set':        Begin Acc[1]:=1;Acc[2]:=0;Acc[3]:=0;Acc[4]:=0;Acc[5]:=0;
                  Result:=Acc;
                End;
  'unset':      Begin Acc[1]:=2;Acc[2]:=0;Acc[3]:=0;Acc[4]:=0;Acc[5]:=0;
                  Result:=Acc;
                End;
  'setcolor':  Begin Acc[1]:=3;Acc[2]:=0;Acc[3]:=0;Acc[4]:=0;Acc[5]:=0;
                  Result:=Acc;
                End;
  'setwidth':   Begin Acc[1]:=4;Acc[2]:=0;Acc[3]:=0;Acc[4]:=0;Acc[5]:=0;
                  Result:=Acc;
                End;
  'setbgcolor': Begin Acc[1]:=5;Acc[2]:=0;Acc[3]:=0;Acc[4]:=0;Acc[5]:=0;
                  Result:=Acc;
                End;
  'setfont':    Begin Acc[1]:=6;Acc[2]:=0;Acc[3]:=0;Acc[4]:=0;Acc[5]:=0;
                  Result:=Acc;
                End;
  'floodfill':  Begin Acc[1]:=7;Acc[2]:=0;Acc[3]:=0;Acc[4]:=0;Acc[5]:=0;
                  Result:=Acc;
                End;
  'ellipse':    Begin
                  Xws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Yws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  X2ws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Y2ws:=ParsedBuf;
                  Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
                  X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
                  Acc[1]:=8;Acc[2]:=Xw;Acc[3]:=Yw;Acc[4]:=X2w;Acc[5]:=Y2w;
                  Result:=Acc;
                End;
  'lineto':     Begin
                  Xws:=GetNextToken(Buf,ParsedBuf,',');
                  Yws:=ParsedBuf;
                  Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
                  Acc[1]:=9;Acc[2]:=Xw;Acc[3]:=Yw;Acc[4]:=0;Acc[5]:=0;
                  Result:=Acc;
                End;
  'moveto':     Begin
                  Xws:=GetNextToken(Buf,ParsedBuf,',');
                  Yws:=ParsedBuf;
                  Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
                  Acc[1]:=10;Acc[2]:=Xw;Acc[3]:=Yw;Acc[4]:=0;Acc[5]:=0;
                  Result:=Acc;
                End;
  'rect':       Begin
                  Xws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Yws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  X2ws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Y2ws:=ParsedBuf;
                  Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
                  X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
                  Acc[1]:=11;Acc[2]:=Xw;Acc[3]:=Yw;Acc[4]:=X2w;Acc[5]:=Y2w;
                  Result:=Acc;
                End;
  'roundrect':  Begin
                  Xws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Yws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  X2ws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Y2ws:=ParsedBuf;
                  Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
                  X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
                  Acc[1]:=12;Acc[2]:=Xw;Acc[3]:=Yw;Acc[4]:=X2w;Acc[5]:=Y2w;
                  Result:=Acc;
                End;
  'circle':     Begin
                  Xws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Yws:=GetNextToken(Buf,ParsedBuf,',');
                  Rws:=ParsedBuf;
                  Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
                  Rw:=StrToFloat(Rws);
                  Acc[1]:=13;Acc[2]:=Xw;Acc[3]:=Yw;Acc[4]:=Rw;Acc[5]:=0;
                  Result:=Acc;
                End;
  'textout':    Begin
                  Xws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Yws:=GetNextToken(Buf,ParsedBuf,',');
                  Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
                  Acc[1]:=14;Acc[2]:=Xw;Acc[3]:=Yw;Acc[4]:=0;Acc[5]:=0;
                  Result:=Acc;
                End;
  'bmp':        Begin
                  Xws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Yws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  X2ws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Y2ws:=GetNextToken(Buf,ParsedBuf,',');
                  Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
                  X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
                  Acc[1]:=15;Acc[2]:=Xw;Acc[3]:=Yw;Acc[4]:=X2w;Acc[5]:=Y2w;
                  Result:=Acc;
                End;
  'subpicture': Begin
                  Xws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Yws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  X2ws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Y2ws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
                  X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
                  Acc[1]:=16;Acc[2]:=Xw;Acc[3]:=Yw;Acc[4]:=X2w;Acc[5]:=Y2w;
                  Result:=Acc;
                End;
  'settextstyle': Begin
                    Acc[1]:=17;Acc[2]:=0;Acc[3]:=0;Acc[4]:=0;Acc[5]:=0;
                    Result:=Acc;
                end;
  'setpenstyle': Begin Acc[1]:=18;Acc[2]:=0;Acc[3]:=0;Acc[4]:=0;Acc[5]:=0;
                  Result:=Acc;
                End;
  'setscaledfont': Begin Acc[1]:=19;Acc[2]:=0;Acc[3]:=0;Acc[4]:=0;Acc[5]:=0;
                  Result:=Acc;
                End;
  'unscaled': Begin
                  Xws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  Yws:=GetNextToken(Buf,ParsedBuf,',');
                  Buf:=ParsedBuf;
                  FName:=GetNextToken(Buf,ParsedBuf,',');
                  Rws:=ParsedBuf;
                  If (Pos('Inf',Xws)<>0)Or(Pos('Inf',Yws)<>0) Then Exit;
                  Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
                  PixR:=StrToInt(Rws);
                  Acc[1]:=20;Acc[2]:=Xw;Acc[3]:=Yw;Acc[4]:=PixR;Acc[5]:=0;
                  Result:=Acc;
                End;
  'textrect': Begin
                Xws:=GetNextToken(Buf,ParsedBuf,',');
                Buf:=ParsedBuf;
                Yws:=GetNextToken(Buf,ParsedBuf,',');
                Buf:=ParsedBuf;
                X2ws:=GetNextToken(Buf,ParsedBuf,',');
                Buf:=ParsedBuf;
                Y2ws:=GetNextToken(Buf,ParsedBuf,',');
                Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
                X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
                Acc[1]:=21;Acc[2]:=Xw;Acc[3]:=Yw;Acc[4]:=X2w;Acc[5]:=Y2w;
                Result:=Acc;
              End
  Else Result:=ZeroAcc;
  end;

end;

Function RenderShell(CommandList:TStrings;M:TMatrix2D):TShell;
Var Cmd,Buf,ParsedBuf,fname:String;
    FBuf:TStringList;
    Color:TColor;
    Xs,Ys,Rs:Longint;xws,yws,Rws:String;
    X2s,Y2s:Longint;x2ws,y2ws:String;
    DisplayList:TStringList;
    Angle:Extended;AngleS:String;
    PicScale:Extended;PicScaleS:String;
    Xw,Yw,Rw:Extended;
    X2w,Y2w:Extended;
    R1,R2:TRect;BM:TBitmap;
    SubDrawer:TDrawer;
    I:Longint;Sm,Rm,Scm,tmpm:TMatrix2D;
    FontFace,FontSize,FontColor,BIUS:String;
    TemplateDisplayList:TStringList;
    ShellX1,ShellX2,ShellY1,ShellY2:Extended;
    SubShell:TShell;
    K,N:Longint;E:TMatrix2D;
    p1,p2:TPoint2D;
Begin
  ShellX1:=Math.maxExtended;
  ShellX2:=-Math.maxExtended;//+Math.minExtended;
  ShellY1:=Math.MaxExtended;
  ShellY2:=-Math.maxExtended;//+Math.minExtended;
  E:=GenShift(0,0);
  If CommandList.Count>0 Then
    For K:=0 To CommandList.Count-1 Do Begin
      Buf:=CommandList[K];
      Cmd:=GetNextToken(Buf,ParsedBuf,' ');
      Buf:=ParsedBuf;
      Case LowerCase(Cmd) Of
      'ellipse','rect','roundrect','textrect'{,'bmp','subpicture'}: Begin
               Xws:=GetNextToken(Buf,ParsedBuf,',');
               Buf:=ParsedBuf;
               Yws:=GetNextToken(Buf,ParsedBuf,',');
               Buf:=ParsedBuf;
               X2ws:=GetNextToken(Buf,ParsedBuf,',');
               Buf:=ParsedBuf;
               Y2ws:=GetNextToken(Buf,ParsedBuf,',');
               Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
               P1[1]:=Xw;P1[2]:=Yw;P1[3]:=1;
               P2:=MulPoint2D(P1,M);
               If P2[1]<ShellX1 Then ShellX1:=P2[1];
               If P2[1]>ShellX2 Then ShellX2:=P2[1];
               If P2[2]<ShellY1 Then ShellY1:=P2[2];
               If P2[2]>ShellY2 Then ShellY2:=P2[2];
               X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
               P1[1]:=X2w;P1[2]:=Y2w;P1[3]:=1;
               P2:=MulPoint2D(P1,M);
               If P2[1]<ShellX1 Then ShellX1:=P2[1];
               If P2[1]>ShellX2 Then ShellX2:=P2[1];
               If P2[2]<ShellY1 Then ShellY1:=P2[2];
               If P2[2]>ShellY2 Then ShellY2:=P2[2];
             End;
      'lineto','moveto': Begin
               Xws:=GetNextToken(Buf,ParsedBuf,',');
               Yws:=ParsedBuf;
               Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
               P1[1]:=Xw;P1[2]:=Yw;P1[3]:=1;
               P2:=MulPoint2D(P1,M);
               If P2[1]<ShellX1 Then ShellX1:=P2[1];
               If P2[1]>ShellX2 Then ShellX2:=P2[1];
               If P2[2]<ShellY1 Then ShellY1:=P2[2];
               If P2[2]>ShellY2 Then ShellY2:=P2[2];
             End;
      'circle': Begin
               Xws:=GetNextToken(Buf,ParsedBuf,',');
               Buf:=ParsedBuf;
               Yws:=GetNextToken(Buf,ParsedBuf,',');
               Rws:=ParsedBuf;
               Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
               Rw:=StrToFloat(Rws);
               P1[1]:=Xw;P1[2]:=Yw;P1[3]:=1;
               P2:=MulPoint2D(P1,M);
               //probably wrong cause R was not scaled
               If (P2[1]-Rw)<ShellX1 Then ShellX1:=(P2[1]-Rw);
               If (P2[1]+Rw)>ShellX2 Then ShellX2:=(P2[1]+Rw);
               If (P2[2]-Rw)<ShellY1 Then ShellY1:=(P2[2]-Rw);
               If (P2[2]+Rw)>ShellY2 Then ShellY2:=(P2[2]+Rw);
             end;
{      'drawtemplate': Begin
               FName:=GetNextToken(Buf,ParsedBuf,' ');
               Buf:=ParsedBuf;
               Xws:=GetNextToken(Buf,ParsedBuf,',');
               Buf:=ParsedBuf;
               Yws:=GetNextToken(Buf,ParsedBuf,',');
               Buf:=ParsedBuf;
               AngleS:=GetNextToken(Buf,ParsedBuf,',');
               PicScaleS:=ParsedBuf;
               Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
               Angle:=StrToFloat(AngleS);
               PicScale:=StrToFloat(PicScaleS);
               Sm:=GenShift(Xw,Yw);
               Rm:=GenRotate(xw,yw,Angle/180*pi);
               Scm:=GenScale(xw,yw,PicScale,PicScale);
               tmpm:=MulMat2D(Sm,Rm);
               tmpm:=MulMat2D(Tmpm,Scm);
               tmpm:=MulMat2D(Tmpm,M);
               N:=VTemplateList.IndexOf(FName);
               If N>=0 Then Begin
                 TemplateDisplayList:=(VTemplateList.Objects[N] As TVTemplate).DisplayList;
                 SubShell:=RenderShell(TemplateDisplayList,tmpm);
                 If SubShell.X1<ShellX1 Then ShellX1:=SubShell.X1;
                 If SubShell.X2>ShellX2 Then ShellX2:=SubShell.X2;
                 If SubShell.Y1<ShellY1 Then ShellY1:=SubShell.Y1;
                 If SubShell.Y2>ShellY2 Then ShellY2:=SubShell.Y2;
               end;
             End;}
      //'unscaled' не должны учитываться при расчёте оболочки, чтении и сохранении дисплейных списков
      //'TextOut' и 'TextRect' в режиме без отсечения невозможно корректно учесть
    end;
  end;
  Result.X1:=ShellX1;
  Result.X2:=ShellX2;
  Result.Y1:=ShellY1;
  Result.Y2:=ShellY2;
end;

Procedure TDrawer.ExecCommand(Command:String;AcceleratedCommand:TAcceleratedCommand);
Var Cmd,Buf,ParsedBuf,fname,URL:String;
    FBuf:TStringList;
    Color:TColor;
    PenStyle:TPenStyle;
    Xs,Ys,Rs:Longint;xws,yws,Rws:String;
    X2s,Y2s:Longint;x2ws,y2ws:String;
    DisplayList:TStringList;
    Angle:Extended;AngleS:String;
    PicScale:Extended;PicScaleS:String;
    Xw,Yw,Rw:Extended; PixR:Longint;
    X2w,Y2w:Extended;
    R1,R2:TRect;BM:TBitmap;
    SubDrawer:TDrawer;
    I,CacheIndex:Longint;Sm,Rm,Scm,tmpm:TMatrix2D;
    CacheItem:TGraphCacheItem;
    FontFace,FontSize,FontColor,BIUS:String;
    TextStyle:TTextStyle;
    MultiLine:TStringList;
    Curl:TVCurl;//temporary shit
    Accelerated:Boolean;
    Picture:TPicture;
    Shell,SubShell:TShell;
begin
    Inc(GOPS);Updated:=True;
    Buf:=ParseLine(Command);
    Cmd:=GetNextToken(Buf,ParsedBuf,' ');
    Buf:=ParsedBuf;
    Accelerated:=True;
    If AcceleratedCommand[1]=0 Then Begin
      Accelerated:=False;
      Case Cmd Of
      'LineTo': AcceleratedCommand[1]:=9;
      'Rect': AcceleratedCommand[1]:=11;
      'MoveTo': AcceleratedCommand[1]:=10;
      'Set': AcceleratedCommand[1]:=1;
      'UnSet': AcceleratedCommand[1]:=2;
      'SetColor': AcceleratedCommand[1]:=3;
      'SetWidth': AcceleratedCommand[1]:=4;
      'SetBGColor': AcceleratedCommand[1]:=5;
      'SetFont': AcceleratedCommand[1]:=6;
      'FloodFill': AcceleratedCommand[1]:=7;
      'Ellipse': AcceleratedCommand[1]:=8;
      'RoundRect': AcceleratedCommand[1]:=12;
      'Circle': AcceleratedCommand[1]:=13;
      'TextOut': AcceleratedCommand[1]:=14;
      'Bmp': AcceleratedCommand[1]:=15;
      'SubPicture': AcceleratedCommand[1]:=16;
      'SetTextStyle': AcceleratedCommand[1]:=17;
      'SetPenStyle': AcceleratedCommand[1]:=18;
      'SetScaledFont': AcceleratedCommand[1]:=19;
      'UnScaled': AcceleratedCommand[1]:=20;
      'TextRect': AcceleratedCommand[1]:=21;

      end;
    end;

    If (AcceleratedCommand[1]=9) Then Begin
      If Accelerated Then Begin
        Xw:=AcceleratedCommand[2];
        Yw:=AcceleratedCommand[3];
      End Else Begin
        Xws:=GetNextToken(Buf,ParsedBuf,',');
        Yws:=ParsedBuf;
        Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
      End;
      WtoS(Xw,Yw,Xs,Ys);
      Canvas.LineTo(Xs,Ys);
      Exit;
    End;
    If  (AcceleratedCommand[1]=11)  Then Begin
      If Accelerated Then Begin
        Xw:=AcceleratedCommand[2];
        Yw:=AcceleratedCommand[3];
        X2w:=AcceleratedCommand[4];
        Y2w:=AcceleratedCommand[5];
      End Else Begin
        Xws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        Yws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        X2ws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        Y2ws:=ParsedBuf;
        Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
        X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
      End;
      WtoS(Xw,Yw,Xs,Ys);
      WtoS(X2w,Y2w,X2s,Y2s);
      Canvas.Rectangle(Xs,Ys,X2s,Y2s);
      Exit;
    End;

    If (AcceleratedCommand[1]=10) Then Begin
      If Accelerated Then Begin
        Xw:=AcceleratedCommand[2];
        Yw:=AcceleratedCommand[3];
      End Else Begin
        Xws:=GetNextToken(Buf,ParsedBuf,',');
        Yws:=ParsedBuf;
        Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
      End;
      WtoS(Xw,Yw,Xs,Ys);
      Canvas.MoveTo(Xs,Ys);
      Exit;
    End;

    If (AcceleratedCommand[1]=1) Then Begin
      Xws:=GetNextToken(Buf,ParsedBuf,'=');
      Yws:=ParsedBuf;
      If VarList.IndexOfName(Xws)<0 Then Begin
        VarList.Add(Xws+'='+Yws);
      End Else Begin
        I:=VarList.IndexOfName(Xws);
        VarList[I]:=Xws+'='+Yws;
      End;
      Exit;
    End;
    If (AcceleratedCommand[1]=2) Then Begin
      If VarList.IndexOfName(ParsedBuf)>=0 Then Begin
        VarList.Delete(VarList.IndexOfName(ParsedBuf));
      End;
      Exit;
    End;
    If (AcceleratedCommand[1]=3) Then Begin
      PenColor:=StringToColor(ParsedBuf);
      If EnforcedPenColor=clNone Then
        Canvas.Pen.Color:=PenColor
      Else Canvas.Pen.Color:=EnforcedPenColor;
      Exit;
    End;
    If (AcceleratedCommand[1]=4) Then Begin
      PenWidth:=(StrToInt(ParsedBuf));
      Canvas.Pen.Width:=(PenWidth-1)*PrintMultiplier+1;
      Exit;
    End;
    If (AcceleratedCommand[1]=5) Then Begin
      BrushColor:=StringToColor(ParsedBuf);
      If EnforcedBrushColor=clNone Then
        Canvas.Brush.Color:=BrushColor
      Else Canvas.Brush.Color:=EnforcedBrushColor;
      Exit;
    End;
    If (AcceleratedCommand[1]=6) Then Begin
      FontFace:=GetNextToken(Buf,ParsedBuf,',');
      Buf:=ParsedBuf;
      FontSize:=GetNextToken(Buf,ParsedBuf,',');
      Buf:=ParsedBuf;
      FontColor:=GetNextToken(Buf,ParsedBuf,',');
      Buf:=ParsedBuf;
      BIUS:=Buf;
      Canvas.Font.Name:=FontFace;
      Canvas.Font.Height:=StrToInt(FontSize);
      Canvas.Font.Color:=StringToColor(FontColor);
      If Pos('b',LowerCase(BIUS))>0 Then
        Canvas.Font.Style:=Canvas.Font.Style+[fsBold]
      Else Canvas.Font.Style:=Canvas.Font.Style-[fsBold];
      If Pos('i',LowerCase(BIUS))>0 Then
        Canvas.Font.Style:=Canvas.Font.Style+[fsItalic]
      Else Canvas.Font.Style:=Canvas.Font.Style-[fsItalic];
      If Pos('u',LowerCase(BIUS))>0 Then
        Canvas.Font.Style:=Canvas.Font.Style+[fsUnderline]
      Else Canvas.Font.Style:=Canvas.Font.Style-[fsUnderline];
      If Pos('s',LowerCase(BIUS))>0 Then
        Canvas.Font.Style:=Canvas.Font.Style+[fsStrikeOut]
      Else Canvas.Font.Style:=Canvas.Font.Style-[fsStrikeOut];
      Exit;
    End;

    If (AcceleratedCommand[1]=7) Then Begin
      Xws:=GetNextToken(Buf,ParsedBuf,',');
      Buf:=ParsedBuf;
      Yws:=GetNextToken(Buf,ParsedBuf,',');
      Color:=StringToColor(ParsedBuf);
      If Accelerated Then Begin
        Xw:=AcceleratedCommand[2];
        Yw:=AcceleratedCommand[3];
      End Else Begin
        Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
      end;
      WtoS(Xw,Yw,Xs,Ys);
      Canvas.Brush.Style:=bsSolid;
      Canvas.FloodFill(Xs,Ys,Color,fsBorder);
      Exit;
    End;

    If (AcceleratedCommand[1]=8) Then Begin
      If Accelerated Then Begin
        Xw:=AcceleratedCommand[2];
        Yw:=AcceleratedCommand[3];
        X2w:=AcceleratedCommand[4];
        Y2w:=AcceleratedCommand[5];
      End Else Begin
        Xws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        Yws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        X2ws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        Y2ws:=ParsedBuf;
        Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
        X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
      End;
      WtoS(Xw,Yw,Xs,Ys);
      WtoS(X2w,Y2w,X2s,Y2s);
      Canvas.Ellipse(Xs,Ys,X2s,Y2s);
      Exit;
    End;

    If (AcceleratedCommand[1]=12) Then Begin
      If Accelerated Then Begin
        Xw:=AcceleratedCommand[2];
        Yw:=AcceleratedCommand[3];
        X2w:=AcceleratedCommand[4];
        Y2w:=AcceleratedCommand[5];
      End Else Begin
        Xws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        Yws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        X2ws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        Y2ws:=ParsedBuf;
        Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
        X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
      End;
      WtoS(Xw,Yw,Xs,Ys);
      WtoS(X2w,Y2w,X2s,Y2s);
      Canvas.RoundRect(Xs,Ys,X2s,Y2s,20,20);
      Exit;
    End;

    If (AcceleratedCommand[1]=13) Then Begin
      If Accelerated Then Begin
        Xw:=AcceleratedCommand[2];
        Yw:=AcceleratedCommand[3];
        Rw:=AcceleratedCommand[4];
      End Else Begin
        Xws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        Yws:=GetNextToken(Buf,ParsedBuf,',');
        Rws:=ParsedBuf;
        Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
        Rw:=StrToFloat(Rws);
      End;
      WtoS(Xw,Yw,Xs,Ys);
      Rs:=Round(Rw/ViewScale);
      Canvas.EllipseC(Xs,Ys,Rs,Rs);
      Exit;
    End;

    If (AcceleratedCommand[1]=14) Then Begin
      Xws:=GetNextToken(Buf,ParsedBuf,',');
      Buf:=ParsedBuf;
      Yws:=GetNextToken(Buf,ParsedBuf,',');
      FName:=ParsedBuf;
      If Accelerated Then Begin
        Xw:=AcceleratedCommand[2];
        Yw:=AcceleratedCommand[3];
      End Else Begin
        Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
      End;
      WtoS(Xw,Yw,Xs,Ys);
      If EnforcedPenStyle=psClear Then
    //    If (Canvas.GetTextWidth('Щ')>5) And (Canvas.GetTextHeight('|')>5) Then
          If Abs(Canvas.Font.Height)>5 Then
          Canvas.TextRect(Rect(Xs,Ys,Xs+Canvas.GetTextWidth(FName),Ys+Canvas.GetTextHeight(FName)),Xs,Ys,FName,Canvas.TextStyle);
      Exit;
    End;

    If (AcceleratedCommand[1]=15) Then Begin
        Xws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        Yws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        X2ws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        Y2ws:=GetNextToken(Buf,ParsedBuf,',');
        URL:=ParsedBuf;

        If Accelerated Then Begin
          Xw:=AcceleratedCommand[2];
          Yw:=AcceleratedCommand[3];
          X2w:=AcceleratedCommand[4];
          Y2w:=AcceleratedCommand[5];
        End Else Begin
          Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
          X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
        End;
        WtoS(Xw,Yw,Xs,Ys);
        WtoS(X2w,Y2w,X2s,Y2s);
        //доступ к кешу
        If URL='' Then Exit;
        CacheIndex:=GraphCache.IndexOf(URL);
        If CacheIndex>=0 Then Begin
          Bm:=(GraphCache.Objects[CacheIndex] As TGraphCacheItem).PixData;
        End Else begin
          BM:=TBitmap.Create;
          Picture:=TPicture.Create;
          LoadImageFromURL(ExpandURL(URL),Picture);
          Bm.Assign(Picture.Graphic);
          Picture.Free;
          CacheItem:=TGraphCacheItem.Create(URL,'pix');
          CacheItem.PixData:=BM;
          CacheItem.LinkCount:=1;
        End;

      R1.Left:=0;R1.Bottom:=Bm.Height;
      R1.Top:=0;R1.Right:=Bm.Width;
      R2.Left:=Min(Xs,X2s);
      R2.Top:=Min(Ys,Y2s);
{      R2.Right:=Xs+Round(Bm.Width/ViewScale);
      R2.Bottom:=Ys+Round(Bm.Height/ViewScale);}
      R2.Right:=Max(Xs,X2s);
      R2.Bottom:=Max(Ys,Y2s);
      If Bm<>Nil Then
        Canvas.CopyRect(R2,Bm.Canvas,R1);
    //  Bm.Free;
      Exit;
    End;

    If (AcceleratedCommand[1]=16) Then Begin
      Xws:=GetNextToken(Buf,ParsedBuf,',');
      Buf:=ParsedBuf;
      Yws:=GetNextToken(Buf,ParsedBuf,',');
      Buf:=ParsedBuf;
      {AngleS:=GetNextToken(Buf,ParsedBuf,',');
      Buf:=ParsedBuf;
      PicScaleS:=GetNextToken(Buf,ParsedBuf,',');
      URL:=ParsedBuf;}
      X2ws:=GetNextToken(Buf,ParsedBuf,',');
      Buf:=ParsedBuf;
      Y2ws:=GetNextToken(Buf,ParsedBuf,',');
      URL:=ParsedBuf;

      If Accelerated Then Begin
        Xw:=AcceleratedCommand[2];
        Yw:=AcceleratedCommand[3];
        X2w:=AcceleratedCommand[4];
        Y2w:=AcceleratedCommand[5];
        {Angle:=AcceleratedCommand[4];
        PicScale:=AcceleratedCommand[5];}
      End Else Begin
        Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
        X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
{        Angle:=StrToFloat(AngleS);
        PicScale:=StrToFloat(PicScaleS);}
      End;

      //доступ к кешу
      CacheIndex:=GraphCache.IndexOf(URL);
      If CacheIndex>=0 Then Begin
        FBuf:=(GraphCache.Objects[CacheIndex] As TGraphCacheItem).TxtData;
      End Else Begin
        FBuf:=TStringList.Create;
        LoadTextFromURL(ExpandURL(URL),FBuf);
        CacheItem:=TGraphCacheItem.Create(URL,'txt');
        CacheItem.TxtData:=FBuf;
        CacheItem.LinkCount:=1;
      End;
      If URL='' Then Exit;
      SubShell:=RenderShell(FBuf,E);
      //x1=x*cos A-y*sin A
      //y1=x*sin A+y*cos A
      Sm:=GenShift(Xw,Yw);
      Angle:=0;
      Rm:=GenRotate(xw,yw,Angle/180*pi);
      //sign problem on y axis?
      Scm:=GenScale(xw,yw,(X2w-Xw)/(SubShell.X2-SubShell.X1),Abs(Y2w-Yw)/Abs(SubShell.Y2-SubShell.Y1));

      tmpm:=MulMat2D(Sm,Rm);
      tmpm:=MulMat2D(Tmpm,Scm);
      SubDrawer:=TDrawer.Create(Canvas);
      Subdrawer.EnforcedPenStyle:=EnforcedPenStyle;
      Subdrawer.EnforcedPenColor:=EnforcedPenColor;
      Subdrawer.EnforcedBrushColor:=EnforcedBrushColor;
      SubDrawer.TransM:=MulMat2D(TmpM,TransM);
      SubDrawer.ViewScale:=Self.ViewScale{/(Abs(Y2w-Yw)/Abs(SubShell.Y2-SubShell.Y1))};
      SubDrawer.Wx:=Wx;
      SubDrawer.Wy:=Wy;
      SubDrawer.VarList:=VarList;

      If FBuf.Count>0 Then
        For I:=0 To FBuf.Count-1 Do Begin
          SubDrawer.ExecCommand(FBuf[I],ZeroAcc);
        End;
    //  FBuf.Free;
      SubDrawer.Free;
      Canvas.Pen.Width:=PenWidth;
      Canvas.Pen.Color:=PenColor;
   End;

    If (AcceleratedCommand[1]=17) Then Begin
     TextStyle:=Canvas.TextStyle;
     If LowerCase(ParsedBuf)='transparent' Then TextStyle.Opaque:=False
     Else TextStyle.Opaque:=True;
     Canvas.TextStyle:=TextStyle;
   End;

   If (AcceleratedCommand[1]=18) Then Begin
     PenStyle:=psSolid;
     Case ParsedBuf Of
     'psSolid':PenStyle:=psSolid;
     'psDash': PenStyle:=psDash;
     'psDot': PenStyle:=psDot;
     'psDashDot':PenStyle:=psDashDot;
     'psDashDotDot':PenStyle:=psDashDotDot;
     'psInsideFrame':PenStyle:=psInsideFrame;
     'psPattern':PenStyle:=psPattern;
     'psClear':PenStyle:=psClear;
     End;
     If EnforcedPenStyle=psClear Then
       Canvas.Pen.Style:=PenStyle
     Else Canvas.Pen.Style:=EnforcedPenStyle;
     Exit;
   End;

   If (AcceleratedCommand[1]=19) Then Begin
      FontFace:=GetNextToken(Buf,ParsedBuf,',');
      Buf:=ParsedBuf;
      FontSize:=GetNextToken(Buf,ParsedBuf,',');
      Buf:=ParsedBuf;
      FontColor:=GetNextToken(Buf,ParsedBuf,',');
      Buf:=ParsedBuf;
      BIUS:=Buf;
      Canvas.Font.Name:=FontFace;
      Canvas.Font.Height:=Round(StrToFloat(FontSize)/Self.ViewScale);
      Canvas.Font.Color:=StringToColor(FontColor);
      If Pos('b',LowerCase(BIUS))>0 Then
        Canvas.Font.Style:=Canvas.Font.Style+[fsBold]
      Else Canvas.Font.Style:=Canvas.Font.Style-[fsBold];
      If Pos('i',LowerCase(BIUS))>0 Then
        Canvas.Font.Style:=Canvas.Font.Style+[fsItalic]
      Else Canvas.Font.Style:=Canvas.Font.Style-[fsItalic];
      If Pos('u',LowerCase(BIUS))>0 Then
        Canvas.Font.Style:=Canvas.Font.Style+[fsUnderline]
      Else Canvas.Font.Style:=Canvas.Font.Style-[fsUnderline];
      If Pos('s',LowerCase(BIUS))>0 Then
        Canvas.Font.Style:=Canvas.Font.Style+[fsStrikeOut]
      Else Canvas.Font.Style:=Canvas.Font.Style-[fsStrikeOut];
      Exit;
   End;

   If  (AcceleratedCommand[1]=20) Then Begin
       Xws:=GetNextToken(Buf,ParsedBuf,',');
       Buf:=ParsedBuf;
       Yws:=GetNextToken(Buf,ParsedBuf,',');
       Buf:=ParsedBuf;
       FName:=GetNextToken(Buf,ParsedBuf,',');
       Rws:=ParsedBuf;
       PixR:=StrToInt(Rws);
       If Accelerated Then Begin
         Xw:=AcceleratedCommand[2];
         Yw:=AcceleratedCommand[3];
       End Else Begin
         Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
       End;
       WtoS(Xw,Yw,Xs,Ys);
       Case FName Of
       'portbox': Begin
                    Canvas.Pen.Width:=1;
                    Canvas.Pen.Color:=clRed;
                    Canvas.Brush.Color:=clYellow;
                    Canvas.Rectangle(Xs-PixR*PrintMultiplier,Ys-PixR*PrintMultiplier,Xs+PixR*PrintMultiplier,Ys+PixR*PrintMultiplier);
                  end;
       'box': Begin
                Canvas.Pen.Width:=1;
                Canvas.Pen.Color:=clBlack;
                Canvas.Brush.Color:=clWhite;
                Canvas.Rectangle(Xs-PixR*PrintMultiplier,Ys-PixR*PrintMultiplier,Xs+PixR*PrintMultiplier,Ys+PixR*PrintMultiplier);
              End;
       'circle': Begin
                  Canvas.Ellipse(Xs-PixR*PrintMultiplier,Ys-PixR*PrintMultiplier,Xs+PixR*PrintMultiplier,Ys+PixR*PrintMultiplier);
                 End;
       'cross': Begin
                  Canvas.MoveTo(Xs-PixR,Ys-PixR);
                  Canvas.LineTo(Xs+PixR,Ys+PixR);
                  Canvas.MoveTo(Xs-PixR,Ys+PixR);
                  Canvas.LineTo(Xs+PixR,Ys-PixR);
                End;
       'plus': Begin
                 Canvas.MoveTo(Xs-PixR,Ys);
                 Canvas.LineTo(Xs+PixR,Ys);
                 Canvas.MoveTo(Xs,Ys+PixR);
                 Canvas.LineTo(Xs,Ys-PixR);
              End;
       'LT': Begin
               Canvas.Pen.Width:=PixR;
               Canvas.Pen.Color:=clYellow;
               Canvas.Brush.Color:=clYellow;
               Canvas.MoveTo(Xs+2*PixR,Ys);
               Canvas.LineTo(Xs,Ys);
               Canvas.LineTo(Xs,Ys+2*PixR);
             end;
       'MT','MB': Begin
               Canvas.Pen.Width:=PixR;
               Canvas.Pen.Color:=clYellow;
               Canvas.Brush.Color:=clYellow;
               Canvas.MoveTo(Xs-2*PixR,Ys);
               Canvas.LineTo(Xs+2*PixR,Ys);
             end;
       'RT': Begin
               Canvas.Pen.Width:=PixR;
               Canvas.Pen.Color:=clYellow;
               Canvas.Brush.Color:=clYellow;
               Canvas.MoveTo(Xs-2*PixR,Ys);
               Canvas.LineTo(Xs,Ys);
               Canvas.LineTo(Xs,Ys+2*PixR);
             end;
       'LB': Begin
               Canvas.Pen.Width:=PixR;
               Canvas.Pen.Color:=clYellow;
               Canvas.Brush.Color:=clYellow;
               Canvas.MoveTo(Xs+2*PixR,Ys);
               Canvas.LineTo(Xs,Ys);
               Canvas.LineTo(Xs,Ys-2*PixR);
             end;
       'RB': Begin
               Canvas.Pen.Width:=PixR;
               Canvas.Pen.Color:=clYellow;
               Canvas.Brush.Color:=clYellow;
               Canvas.MoveTo(Xs-2*PixR,Ys);
               Canvas.LineTo(Xs,Ys);
               Canvas.LineTo(Xs,Ys-2*PixR);
             end;
       'LM','RM': Begin
               Canvas.Pen.Width:=PixR;
               Canvas.Pen.Color:=clYellow;
               Canvas.Brush.Color:=clYellow;
               Canvas.MoveTo(Xs,Ys-2*PixR);
               Canvas.LineTo(Xs,Ys+2*PixR);
             end;

       Else Begin
              Canvas.Pen.Width:=1;
              Canvas.Pen.Color:=clRed;
              Canvas.Brush.Color:=clYellow;
              Canvas.Rectangle(Xs-PixR*PrintMultiplier,Ys-PixR*PrintMultiplier,Xs+PixR*PrintMultiplier,Ys+PixR*PrintMultiplier);
            end;
       end;
       Exit;
     End;

     If (AcceleratedCommand[1]=21) Then Begin
       Xws:=GetNextToken(Buf,ParsedBuf,',');
       Buf:=ParsedBuf;
       Yws:=GetNextToken(Buf,ParsedBuf,',');
       Buf:=ParsedBuf;
       X2ws:=GetNextToken(Buf,ParsedBuf,',');
       Buf:=ParsedBuf;
       Y2ws:=GetNextToken(Buf,ParsedBuf,',');
       FName:=ParsedBuf;
       MultiLine:=TStringList.Create;
       MultiLine.CommaText:=FName;
       If Accelerated Then Begin
         Xw:=AcceleratedCommand[2];
         Yw:=AcceleratedCommand[3];
         X2w:=AcceleratedCommand[4];
         Y2w:=AcceleratedCommand[5];
       End Else Begin
         Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
         X2w:=StrToFloat(X2ws);Y2w:=StrToFloat(Y2ws);
       End;
       WtoS(Xw,Yw,Xs,Ys);
       WtoS(X2w,Y2w,X2s,Y2s);
       TextStyle:=Canvas.TextStyle;
       TextStyle.Clipping:=True;
       TextStyle.WordBreak:=False;
       TextStyle.SingleLine:=False;
       If EnforcedPenStyle=psClear Then
         If Canvas.Font.Height>5 Then
       //  If (Canvas.GetTextWidth('Щ')<Abs(X2s-Xs)) And (Canvas.GetTextHeight('|')<Abs(Y2s-Ys)) Then
           If (X2w=0) And (Y2w=0) Then Begin
  Canvas.TextRect(Rect(Xs,Ys,Xs+Canvas.GetTextWidth(MultiLine.Text),Ys+Canvas.GetTextHeight(MultiLine.Text)),Xs,Ys,MultiLine.Text,TextStyle);
           end Else
             Canvas.TextRect(Rect(Xs,Ys,X2s,Y2s),Xs,Ys,MultiLine.Text,TextStyle);
       MultiLine.Free;
       Exit;
     End;

  { If Cmd='DrawCurl' Then Begin
      FName:=Buf;
      If Resolver<>NIL Then Begin
        I:=Resolver.IndexOf(FName);
        If I<0 Then LogMessage(1,'Drawer can''t find name in resolver:'+Fname)
        Else Begin
          Curl:=Resolver.Objects[I] As TVCurl;
          DisplayList:=Curl.DisplayList;
          Sm:=GenShift(0,0);
          Rm:=GenRotate(0,0,0);
          Scm:=GenScale(0,0,1,1);
          tmpm:=MulMat2D(Sm,Rm);
          tmpm:=MulMat2D(Tmpm,Scm);
          SubDrawer:=TDrawer.Create(Canvas);
          SubDrawer.TransM:=MulMat2D(tmpm,TransM);
          SubDrawer.Wx:=Wx;
          SubDrawer.Wy:=Wy;
          SubDrawer.VarList:=VarList;
          If DisplayList.Count>0 Then
            For I:=0 To DisplayList.Count-1 Do Begin
              SubDrawer.ExecCommand(DisplayList[I]);
            End;
          SubDrawer.Free;
        End;
      end Else LogMessage(1,'Drawers resolver is NIL');
      Canvas.Pen.Width:=PenWidth;
      Canvas.Pen.Color:=PenColor;
   End;}

End;

initialization
  GraphCache:=TStringList.Create;
end.

