{************************************************************}
{                   Delphi VCL Extensions                    }
{                                                            }
{                  DXF files TGraphic class                  }
{                                                            }
{      Copyright (c) 2002-2007 SoftGold software company     }
{                                                            }
{************************************************************}

unit DXFImage;
{$INCLUDE SGDXF.INC}

interface

uses Windows, Classes, Graphics, Math, MVFont, DXFConv, Extrusion, SHX,
  {$IFNDEF SG_CAD_DLL}
  Forms, Dialogs,
  {$ENDIF}
  SysUtils, SGLines, sgConsts, TTF, sgBitmap, sgSelection
  {$IFDEF SG_USEGDIPLUS}
    , GDIPlus
  {$ENDIF};

//For working with SaveToStream the definition sgFR should be uncommented.
//This is necessary for Fast Report Add-in.
//{$DEFINE sgFR}

type
  TsgDXFDrawMode = (dmNormal, dmBlack, dmGray);
  TsgDXFViewDirection = (vdDefault, vdTop, vdBottom, vdLeft, vdRight, vdFront, vdBack,
     vdSWIsometric, vdSEIsometric, vdNWIsometric, vdNEIsometric);

   TsgSHXFontsProc = function: TsgSHXFontList of object;
   TsgGetSelectionMatrixModeProc = function: TsgSelectionMode of object;
   TsgSetSelectionMatrixModeProc = procedure (const AMode: TsgSelectionMode) of object;


  // Obsolete type
  TScaling = record
    Offset: TFPoint;
    Scale: TFPoint;
    DX: Integer;
    DY: Integer;
  end;

  PsgCanvasParams = ^TsgCanvasParams;
  TsgCanvasParams = record
    Brush: TBrush;
    Font: TFont;
    Pen: TPen;
  end;

  PsgViewPortCanvasParams = ^TsgViewPortCanvasParams;
  TsgViewPortCanvasParams = record
    HDC: HDC;
    CanvasParams: TsgCanvasParams;
  end;

  TsgCalcCoordsStruct = record
    XScaled: Extended;
    YScaled: Extended;
    X: TsgFloat;
    Y: TsgFloat;
    Rot: TFMatrix;
    RealLayoutCenter: TFPoint;
    NullCoord: Integer
  end;

{$IFDEF SGDEL_4}
  PSnapData = ^TSnapData;
  TSnapData = record
    IsSnapPoint: Boolean;
    Entity: TsgDXFEntity;
    SnapMode: TObjectSnapMode;
    CADPoint: TFPoint;
    CADPointInUCS: TFPoint;
  end;
{$ENDIF}

  TsgDistanceUnits = (duNone, duInch, duMM);
  TsgAngularUnits = (auNone);
  TsgMeasurement = record
    DistanceUnits: TsgDistanceUnits;
    AngularUnits: TsgAngularUnits;
  end;

  TsgDXFImage = class;

  TsgDXFImageClass = class of TsgDXFImage;

  TsgDXFImage = class(TGraphic)
  private
    FAngleDefault: Single;
    FBackgroundColor: TColor;
    FBorderSize: TsgBorderSize;
    FBorderType: TsgBorderType;
    FCanvasParams: TsgCanvasParams;
    FCBFormat: Word;
    FCenter: TFPoint;
    FCharset: TFontCharset;
    FClippingRect: PFRect;
    FColorToLineWeight: TStringList;
    FConverter: TsgDXFConverter;
    FConverting: Boolean;
    FCurrentLayout: TsgDXFLayout;
    FCounts: TList;
    FDefaultColor: TColor;
    FDimensionsVisible: Boolean;
    FDrawingBox: TFRect;
    FDrawMode: TsgDXFDrawMode;
    FDX: Double;
    FDY: Double;
    FExportToDXFMode: Boolean;
    FExtents: TFRect;
    FFileInfo: string;
    FIndex: Integer;
    FIntPoints: TList;
    FIPoints: array [0..7] of TPoint;
    FIRect: TRect;
    FIsDraw3DAxes: Boolean;
    FIsPlotting: Boolean;
    FIsProcessMessages: Boolean;
    FIsShowBackground: Boolean;
    FIsShowLineWeight: Boolean;
    FIsWithoutBorder: Boolean;
    FLast: Integer;
    FLineScaled: Boolean;
    FLibraryGDIPlusExists: Boolean;
    FLScale: Double;
    FMillimetres: Integer;
    FmmToPixelX: Double;
    FMsg: string;
    FNullWidth: Integer;
    FOnLayoutChange: TNotifyEvent;
    FOnLayoutBeforeChange: TNotifyEvent;

    //If set in the main CADImage these fields will be set in all internal CADImages.
    FOnInsert: TsgDXFInsert;// -  an insert for which the block entities will be drawn separately on the bitmap.
    FOnInsertMode: Boolean;// - a mode of separate drawing the entities on the bitmap for the diven insert.

    FPoly: TList;
    FPureExtents: TFRect;
    FReady: Boolean;
    FZRotate: Double;
    FSelectionMatrixMode: TsgSelectionMode;
    FScale: TFPoint;
{$IFDEF SGDEL_4}
    FCurrSnapMode: TObjectSnapMode;
    FObjectSnapMode: TObjectSnapMode;
    FSnapEntity: TsgDXFEntity;
    FSnapMatrix: array of array of Pointer;
    FSnapOnlyIterate: Boolean;
    FStoreSnapOnlyIterate: Boolean;
    FStoreInsert: TsgDXFInsert;
{$ENDIF}
    {$IFDEF sgFR}
    FStream: TMemoryStream;
    {$ENDIF}
    FStretch: Boolean;
    FUseWinEllipse: Boolean;
    FShowImages: Boolean;
    FViewPortCanvasParams: PsgViewPortCanvasParams;
    FViewPortRegion: HRGN;
    FClipRegion: HRGN;
    FVisibleArea: TPoint;
    FVPortDefault: TFPoint;
    FXMax: Double;
    FXMin: Double;
    FYMax: Double;
    FYMin: Double;
    FZMax: Double;
    FZMin: Double;
    FZoom: Double;
    FViewRectangle: TFRect;
    FLineWeightScale: TsgFloat;
    FResizeDisproportionateDrawing: Boolean;
    FTextVisible: Boolean;
    FXDisproportionateShift: TsgFloat;
    FYDisproportionateShift: TsgFloat;
    FSHXFontsProc: TsgSHXFontsProc;
    FGetSelectionMatrixModeProc: TsgGetSelectionMatrixModeProc;
    FSetSelectionMatrixModeProc: TsgSetSelectionMatrixModeProc;
    procedure ApplyBrush;
    procedure ApplyPen(Sender: TObject);
    procedure ApplyScale(AWidth,AHeight: Integer);
    procedure ApplyText;
    procedure BeginRead(Sender: TObject);
    procedure BoxPoint(const P: TFPoint);
    function CalcCADCoordsParameters({AXScaled, AYScaled: Extended;
               var AX, AY: TsgFloat; var ARot: TFMatrix;
               var ARealLayoutCenter: TFPoint; var ANullCoord: Integer}var AStruct: TsgCalcCoordsStruct): Boolean;
    function CoordinateBorderCorrect(var AXScaled, AYScaled: Extended): Boolean;
    procedure DoProgress(Stage: TProgressStage);
    procedure DoRead(Sender: TObject);
    procedure DrawArc(Sender: TObject);
    procedure DrawCircle(Sender: TObject);
    procedure DrawFace(Sender: TObject);
    procedure DrawHatch(Sender: TObject);
    function DrawInsert(Sender: TObject): Integer;
    function DrawDimension(Sender: TObject): Integer;
    procedure DrawLeader(Sender: TObject);
    procedure DrawLine(Sender: TObject);
    procedure DrawPoint(Sender: TObject);
    procedure DrawPoly(Sender: TObject);
    procedure DrawACISEntity(Sender: TObject);
    procedure DrawSpline(Sender: TObject);
    procedure DrawSolid(Sender: TObject);
    procedure DrawText(Sender: TObject);
    procedure DrawViewPort(Sender: TObject);
    procedure DrawImage(Sender: TObject);
    procedure DrawFlatPoly(Sender: TObject);
    procedure DrawFlatHatch(Sender: TObject);
    procedure DrawOle2Frame(Sender: TObject);
    procedure DrawPointsListByPolyline(const AObj: TObject; const DottedSingPts: TList);
    procedure DrawPointsListByPolyPolyline(const AObj: TObject; const DottedSingPts: TList);
    procedure DrawXRef(Sender: TObject);
    procedure EndRead(Sender: TObject);
    procedure EnterInsert(Sender: TObject);
    procedure EnterViewport(Sender: TObject);
    procedure EnterXRef(Sender: TObject);
    procedure FillFromFlat(FP: TsgFlatEntity);
    function GetBlock(Index: Integer): TsgDXFBlock;
    function GetEntity(Index: Integer): TsgDXFEntity;
    function GetIs3D: Boolean;
    function GetIsLoading: Boolean;
    function GetIsDrawingRotated: Boolean;
    function GetLayout(Index: Integer): TsgDXFLayout;
    function GetLayoutsCount: Integer;
    function GetLineWeightScale: TsgFloat;
    function GetScale: TFPoint;
    function GetOwnSource: Boolean;
    function GetSHXFontsProc: TsgSHXFontList;
    function GetSelectionMatrixProc: TsgSelectionMode;
    procedure ResetExtents;
    procedure SetBackgroundColor(Value: TColor);
    procedure SetCharset(Value: TFontCharset);
    procedure SetDefaultColor(Value: TColor);
    procedure SetDrawingBox(const ABox: TFRect);
    procedure SetDrawMode(Value: TsgDXFDrawMode);
    procedure SetIs3D(Value: Boolean);
    procedure SetIsShowBackground(Value: Boolean);
    procedure SetIsShowLineWeight(Value: Boolean);
    procedure SetIsWithoutBorder(Value: Boolean);
    procedure SetLineScaled(Value: Boolean);
    procedure SetSelectionMatrixProc(const AMode: TsgSelectionMode);
    procedure SetStretch(Value: Boolean);
    procedure SetLineWeightScale(const Value: TsgFloat);
    procedure SetUseWinEllipse(Value: Boolean);
    procedure SetShowImages(Value: Boolean);
    procedure SetDimensionsVisible(AVisible: Boolean);
    procedure SetTextVisible(AVisible: Boolean);
    procedure SetOwnSource(Value: Boolean);
    procedure SetClip(AInsert: TsgCADClipInsert);
{$IFDEF SGDEL_4}
    procedure DrawEntityOnSnapMatrix(Entity: TsgDXFEntity);
    function IsIndexInArray(Pt: TPoint): Boolean;
    procedure SetupSnapMatrix;
    procedure SetPixelSnap(APt: TFPoint);
{$ENDIF}
  protected
    FCanvas: TCanvas;
    FDraw: TsgCADIterate;
    FExtPenFlag: Byte;
    procedure AddSelectionMatrix(const APointer: Pointer);
    procedure AssignTo(Dest: TPersistent); override;
    procedure ClearMatrices(const ARect: TRect);
    function CreateConverter: TsgDXFConverter; virtual;
    function DoDraw(Entity: TsgDXFEntity): Integer; virtual;
    function DoFinish(Entity: TsgDXFEntity): Integer; virtual;
    procedure Draw3DAxes;
    procedure Draw(Canvas: TCanvas; const Rect: TRect); override;
    function DrawEntity(Entity: TsgDXFEntity): Integer;
    procedure EntityCreated(Sender: TObject);
    procedure FillBoxForCoordsCalc(ACoord: Integer; var ABox: TFRect); virtual;
    function IsDrawOnBitMap: Boolean;
    function IsDrawOnCanvas: Boolean;
    function GetEmpty: Boolean; override;
    function GetFPoint(const P: TFPoint): TFPoint;    
    function GetHeight: Integer; override;
    function GetLineScale: Double; virtual;
    function GetLineWeight(const AWeight: Double): Integer;
    function GetMillimetres: Boolean; virtual;
    function GetPalette: HPalette; override;
    function GetRect(const ARect: TFRect): TRect;
    function GetRealImageMatrix: TFMatrix;
    function GetWidth: Integer; override;
    procedure Progress(Sender: TObject; Stage: TProgressStage;
      PercentDone: Byte;  RedrawNow: Boolean; const R: TRect; const Msg: string);override;
    procedure SetCurrentLayout(const ALayout: TsgDXFLayout);
    procedure SetDefaultViewPort(AConverter: TsgDXFCOnverter);
    procedure SetEntityVisibility(ACADFile: TObject);
    procedure SetExtentsParameters(const ARect: TFRect; const AIs3DExtents: Boolean); virtual;
    procedure SetOnInsertMode(const AIns: TsgDXFInsert);
    procedure SetHeight(Value: Integer); override;
    procedure SetMatrix; virtual;
    procedure SetMillimetres(Value: Boolean); virtual;
    procedure SetWidth(Value: Integer); override;
    procedure TransformToUCS(var APoint: TFPoint);
    procedure TransformToWorldCS(var APoint: TFPoint);
    property FColor: TColor read FDraw.Color write FDraw.Color;
    property FHCoef: Single read FDraw.YScale write FDraw.YScale;
    property FAngle: Single read FDraw.Angle write FDraw.Angle;
    property FileInfo: string read FFileInfo write FFileInfo;
    property OnLayoutBeforeChange: TNotifyEvent read FOnLayoutBeforeChange write FOnLayoutBeforeChange;
    property LibraryGDIPlusExists: Boolean read FLibraryGDIPlusExists write FLibraryGDIPlusExists;
    {$IFDEF sgFR}
    property Stream: TMemoryStream read FStream write FStream;
    {$ENDIF}
     property SHXFontsProc: TsgSHXFontsProc read FSHXFontsProc{ write FSHXFontsProc};
     property GetMatrixMode: TsgGetSelectionMatrixModeProc read FGetSelectionMatrixModeProc;
     property SetMatrixMode: TsgSetSelectionMatrixModeProc read FSetSelectionMatrixModeProc;
  public
    constructor Create; override;
    destructor Destroy; override;
    function AbsHeight: Extended;
    function AbsWidth: Extended;
    procedure AddScaledDXF(ACADFile: TObject; AName: string; APos, AScale: TFPoint; Rotation: Single);
    function AddScaledDXFEx(ACADFile: TObject; AName: string; APos, AScale: TFPoint; Rotation: Single): TsgDXFInsert;
    procedure Assign(Source: TPersistent); override;
    function CommonToInternalUnits(Pt: TFPoint): TFPoint; virtual;
{$IFDEF SGDEL_4}
    procedure ExportToMetafile(const FileName: string; AWidth,AHeight: Integer);
      overload;
    function ExportToMetafile(AWidth,AHeight: Integer): TMetafile; overload;
    function ExportToMetafile(MaxDim: Integer): TMetafile; overload;
    function ExportToMetafile(var OffsetX, OffsetY, UnitSize: TsgFloat): TMetafile; overload;
{$ELSE}
    procedure ExportToMetafile(const FileName: string; AWidth,AHeight: Integer);
{$ENDIF}
   procedure DrawRect(DC: HDC; SourceRect: TFRect; DestRect: TRect);
   procedure GetExtents;
{$IFDEF SGDEL_4}
   function GetCADCoords(const AXScaled, AYScaled: Extended): TFPoint; overload;
   function GetCADCoords(const AXScaled, AYScaled: Extended; var CoordsInUCS: TFPoint): TFPoint; overload;
{$ELSE}
   function GetCADCoords(const AXScaled, AYScaled: Extended): TFPoint;
{$ENDIF}
   function GetEntityColor(AEntity: TsgDXFEntity; AInsert: TsgDXFInsert): TColor; virtual;
   function GetPoint(const P: TFPoint): TPoint;
   function GetPointUCS(P: TFPoint): TPoint;
   function GetRealImagePoint(const P: TFPoint): TFPoint;
{$IFDEF SGDEL_4}
   function GetSnapData(const P: TPoint): PSnapData;
   function GetObjectSnapMode: TObjectSnapMode;
   procedure SetObjectSnapMode(AValue: TObjectSnapMode);
{$ENDIF}
   function HeadVarAsInteger(const AName: string; ACode: Integer): Integer;
   function HeadVarAsFloat(const AName: string; ACode: Integer): Extended;
   function HeadVarAsstring(const AName: string; ACode: Integer): string;
   function InternalToCommonUnits(Pt: TFPoint): TFPoint; virtual;
   procedure LoadFromClipboardFormat(Fmt: Word; Data: THandle; Pal: HPALETTE); override;
   procedure LoadFromFile(const FileName: string); override;
   procedure LoadFromStream(S: TStream); override;
   function Measurement: TsgMeasurement; virtual;
   procedure RefreshCurrentLayout;
   procedure ResetDrawingBox;
   procedure Rotate(Axis: TsgAxes; Angle: Extended);
   procedure RotDefault;
   procedure RotToView(const A3DView: TsgDXFViewDirection);
   procedure SaveToClipboardFormat(var Fmt: Word; var Data: THandle; var Pal: HPALETTE); override;
   procedure SaveToFile(const FileName: string); override;
   procedure SaveToStream(S: TStream); override;
   procedure SetClippingRect(Value: PFRect);// not documented, only for internal using (!)
   procedure SetVisibleArea(Data: TPoint);
   procedure StopLoading; virtual;
   property BackgroundColor: TColor read FBackgroundColor write SetBackgroundColor;
   property Blocks [Index: Integer]: TsgDXFBlock read GetBlock;
   property BorderSize: TsgBorderSize read FBorderSize write FBorderSize;
   property BorderType: TsgBorderType read FBorderType write FBorderType;
   property CBFormat: Word read FCBFormat write FCBFormat;
   property Charset: TFontCharset read FCharset write SetCharset;
   property ClippingRect: PFRect read FClippingRect write SetClippingRect;// not documented, only for internal using (!)
   property ColorToLineWeight: TStringList read FColorToLineWeight;
   property Converter: TsgDXFConverter read FConverter;
   property CurrentLayout: TsgDXFLayout read FCurrentLayout write SetCurrentLayout;
   property DefaultColor: TColor read FDefaultColor write SetDefaultColor;
   property DrawingBox: TFRect read FDrawingBox write SetDrawingBox;
   property DrawMode: TsgDXFDrawMode read FDrawMode write SetDrawMode;
   property Entities [Index: Integer]: TsgDXFEntity read GetEntity;
   property Extents: TFRect read FExtents write FExtents;
   property Is3D: Boolean read GetIs3D write SetIs3D;
   property IsDraw3DAxes: Boolean read FIsDraw3DAxes write FIsDraw3DAxes;
   property IsLoading: Boolean read GetIsLoading;
   property IsPlotting: Boolean read FIsPlotting write FIsPlotting;
   property IsProcessMessages: Boolean read FIsProcessMessages write FIsProcessMessages;
   property IsDrawingRotated: Boolean read GetIsDrawingRotated;
   property IsShowBackground: Boolean read FIsShowBackground write SetIsShowBackground;
   property IsShowLineWeight: Boolean read FIsShowLineWeight write SetIsShowLineWeight;
   property IsWithoutBorder: Boolean read FIsWithoutBorder write SetIsWithoutBorder;
   property Layouts[Index: Integer]: TsgDXFLayout read GetLayout;
   property LayoutsCount: Integer read GetLayoutsCount;
   property LineScaled: Boolean read FLineScaled write SetLineScaled;
   property LineWeightScale: TsgFloat read GetLineWeightScale write SetLineWeightScale;
   property Millimetres: Boolean read GetMillimetres write SetMillimetres;
   property NullWidth: Integer read FNullWidth write FNullWidth;
   property OnLayoutChange: TNotifyEvent read FOnLayoutChange write FOnLayoutChange;
   property PureExtents: TFRect read FPureExtents;
   property ResizeDisproportionateDrawing: Boolean read FResizeDisproportionateDrawing
                                                  write FResizeDisproportionateDrawing;
   property ShowImages: Boolean read FShowImages write SetShowImages;
   property Scale: TFPoint read GetScale;
   property Stretch: Boolean read FStretch write SetStretch;
   property UseWinEllipse: Boolean read FUseWinEllipse write SetUseWinEllipse;
   property ViewRectangle: TFRect read FViewRectangle write FViewRectangle;
   property DimensionsVisible: Boolean read FDimensionsVisible write SetDimensionsVisible;
   property TextVisible: Boolean read FTextVisible write SetTextVisible;
   property OwnSource: Boolean read GetOwnSource write SetOwnSource;
end;

  procedure RotateBitmap(Bitmap: TBitmap; Angle: Double; BackColor: TColor);
  procedure RotatePicture(Picture: TPicture; Angle: Double; BackColor: TColor);


var
  CF_DXF: Word;
  Drawing: TsgDXFImage;
  MinDXFSize: Integer;

{$IFNDEF BCB}
threadvar
  Loading: TsgDXFImage;
{$ELSE}
var
  Loading: TsgDXFImage;
{$ENDIF}


implementation
uses
  ActiveX, ComObj, DXF;

type
  PTriVertex = ^TTriVertex;
  TTriVertex = record
    X,Y: Integer;
    Red,Green,Blue,Alpha: Word;
  end;
  TGradFill = function(DC: HDC; PV: PTriVertex; NumV: Integer; PMesh: Pointer; NMesh,Mode: Integer): LongBool; stdcall;
  TsgCADGradientPolygonAccess = class(TsgCADGradientPolygon);
  TsgDXFImageEntAccess = class(TsgDXFImageEnt);
  TsgDXFPointAccess = class(TsgDXFPoint);
  TsgBitmapAccess = class(TsgBitMap);

var
  AcadPal: HPalette;
  Msimg32: THandle;
  GradientFill: TGradFill;

function PLibraryGDIPlusExists: Boolean;
{$IFDEF SG_USEGDIPLUS}
// Use GDI +
var
  GdiPlus: THandle;
{$ENDIF}
begin
{$IFDEF SG_USEGDIPLUS}
  GdiPlus := 0;
  try
    GdiPlus := LoadLibrary('GdiPlus.dll');
  finally
    Result := GdiPlus <> 0;
    FreeLibrary(GdiPlus);
  end;
{$ELSE}
  Result := False;
{$ENDIF}
end;

function GFStub(DC: HDC; PV: PTriVertex; NumV: Integer; PMesh: Pointer; NMesh,Mode: Integer): LongBool; stdcall;
var
  HBr: HBrush;
  R: TRect;
begin
  Result := NumV > 1;
  if not Result then Exit;
  R.TopLeft := Point(PV.X, PV.Y); Inc(PV);
  R.BottomRight := Point(PV.X, PV.Y); Dec(PV);
  HBr := CreateSolidBrush(PV.Red and $FF00 shr 8 + PV.Green and $FF00 + PV.Blue and $FF00 shl 8);
  FillRect(DC,R,HBr);
  DeleteObject(HBr);
end;

procedure InitGradFill;
begin
  GradientFill := GFStub;
  Msimg32 := LoadLibrary('msimg32.dll');
  if Msimg32 <> 0 then GradientFill := GetProcAddress(Msimg32,'GradientFill');
end;

procedure CreateAcadPal;
var
  I: Integer;
  P: TMaxLogPalette;
  LP: TLogPalette absolute P;
begin
  P.palVersion := $300;
  P.palNumEntries := 216;
  for I:=0 to 215 do
  begin
    P.palPalEntry[I].peRed := I mod 6 * 51;
    P.palPalEntry[I].peGreen := I div 6 mod 6 * 51;
    P.palPalEntry[I].peBlue := I div 36 * 51;
    P.palPalEntry[I].peFlags := 0;
  end;
  AcadPal := CreatePalette(LP);
end;

function GetAngleByPoints(const ACenter, APoint: TPoint): Double;
var
  vKatet, vCmp: TPoint;
begin
  vKatet := Point(APoint.X - ACenter.X, APoint.Y - ACenter.Y);
  vCmp := Point(Integer(vKatet.X < 0), Integer(vKatet.Y < 0));
  vKatet := Point(Abs(vKatet.X), Abs(vKatet.Y));
  if vKatet.X = 0 then
    Result := 90 + 180 * vCmp.Y
  else
  begin
    Result := f180DividedByPi * ArcTan(vKatet.Y / vKatet.X);
    case vCmp.X shl 1 + vCmp.Y of
      1:  Result := 360 - Result;
      2:  Result := 180 - Result;
      3:  Result := 180 + Result;
    end;
  end
end;

function GetPointOfRotateByCenter(const APoint, ACenter: TPoint; const Angle: Double): TPoint;
var
  vAngle, vDistance, vDX, vDY: Double;
  S, C: Extended;
begin
  vDX := APoint.X - ACenter.X;
  vDY := APoint.Y - ACenter.Y;
  vDistance := vDX * vDX + vDY * vDY;
  if vDistance > fAccuracy then
    vDistance := Sqrt(vDistance)
  else
    vDistance := 0;
  vAngle := (GetAngleByPoints(ACenter, APoint) + Angle) * fPiDividedBy180;
  SinCos(vAngle, S, C);
  Result.X := ACenter.X + Round(vDistance * C);
  Result.Y := ACenter.Y + Round(vDistance * S);
end;

procedure RotatePicture(Picture: TPicture; Angle: Double; BackColor: TColor);
var
  SG: TsgBitmap;
  Bitmap: TGraphic;
begin
  Bitmap := Picture.Graphic;
  if Bitmap is TsgBitmap then begin
    TsgBitmap(Bitmap).Rotate(Round(Angle));
    Exit;
  end;
  if not (Bitmap is TBitmap) then Exit;
  SG := TsgBitmap.Create;
  try
    SG.Assign(Bitmap);
    SG.Rotate(Round(Angle));
    Picture.Graphic := SG;
  finally
    SG.Free;
  end;
end;

procedure RotateBitmap(Bitmap: TBitmap; Angle: Double; BackColor: TColor);
const
  cnstMaxBmpHeight = 8191;
type
  TRGB = record
    B, G, R: Byte;
  end;
  pRGB = ^TRGB;
var
  x, y, W, H, v1, v2: Integer;
  Dest, Src: pRGB;
  VertArray: array[0..cnstMaxBmpHeight] of pByteArray;
  Bmp: TBitmap;
begin
  Angle := Angle - Floor(Angle / 360) * 360;
  try
    while Angle < 0 do
    Angle := Angle + 360;
    Bitmap.PixelFormat := pf24Bit;
    Bmp := TBitmap.Create;
    try
      Bmp.Assign(Bitmap);
      Bmp.FreeImage;
      W := Bitmap.Width - 1;
      H := Bitmap.Height - 1;
      if H > cnstMaxBmpHeight then
        H := cnstMaxBmpHeight;
      case Trunc(Angle) of
        90, 270:
        begin
          Bitmap.Width := H + 1;
          Bitmap.Height := W + 1;
          v1 := 0;
          v2 := 0;
          if Trunc(Angle) = 90 then
            v1 := H
          else
            v2 := W;
          for y := 0 to H do
            VertArray[y] := Bmp.ScanLine[Abs(v1 - y)];
          for x := 0 to W do
          begin
            Dest := Bitmap.ScanLine[x];
            for y := 0 to H do
            begin
              v1 := Abs(v2 - x)*3;
              with Dest^ do
              begin
                B := VertArray[y, v1];
                G := VertArray[y, v1+1];
                R := VertArray[y, v1+2];
              end;
              Inc(Dest);
            end;
          end
        end;
        180:
        begin
          for y := 0 to H do
          begin
            Dest := Bitmap.ScanLine[y];
	          Src := Bmp.ScanLine[H - y];
            Inc(Src, W);
            for x := 0 to W do
            begin
              Dest^ := Src^;
              Dec(Src);
              Inc(Dest);
            end;
          end;
        end;
      end;
    finally
      Bmp.Free;
    end;
    if not Bitmap.Modified then Bitmap.Modified := True;
  except
  end;
end;

procedure DrawPolyLine(DC: HDC; IntPoints: TList);
begin
  Windows.Polyline(DC, IntPoints.List^, IntPoints.Count shr 1);
end;

procedure DrawPolyPolyLine(DC: HDC; IntPoints: TList);
var
  I, N, C: Integer;
  P: Pointer;
begin
  N := IntPoints.Count shr 2;
  if N = 0 then
    Exit;
  C := IntPoints.Count;
  for I := 0 to N - 1 do
    IntPoints.Add(Pointer(2));
  P := IntPoints.List;
  Inc(PInteger(P), C);
  PolyPolyline(DC, IntPoints.List^, P^, N);
end;

procedure DrawPolyPolyLineEx(DC: HDC; IntPoints: TList; APenWidth: Integer);
var
  I, C, N: Integer;
  P: Pointer;
begin
  N := (IntPoints.Count shr 2) - 1;
  if N < 0 then
    Exit;
  if APenWidth <= 1 then
  begin
    // Works very slow for big width of pen
    C := IntPoints.Count;
    for I := 0 to N do
      IntPoints.Add(Pointer(2));
    P := IntPoints.List;
    Inc(PInteger(P), C);
    PolyPolyline(DC, IntPoints.List^, P^, N+1);
  end
  else
    for I := 0 to N do
      Polyline(DC, IntPoints.List^[I shl 2], 2);
end;

{ TsgDXFImage }

constructor TsgDXFImage.Create;
begin
  LibraryGDIPlusExists := PLibraryGDIPlusExists;
  FLineWeightScale := 1.0;
  FViewRectangle := BadRect;
  FCBFormat := CF_DXF;
  FConverter := CreateConverter;
  FPoly := TList.Create;
  FCanvasParams.Brush := TBrush.Create;
  FCanvasParams.Font := TFont.Create;
  FCanvasParams.Pen := TPen.Create;
  FCharset := DEFAULT_CHARSET;
  FConverter.OnCreate := EntityCreated;
  FConverter.BeforeRead := BeginRead;
  FConverter.AfterRead := EndRead;
  FConverter.OnRead := DoRead;
  FLineScaled := True;
  FStretch := True;
  FIsShowBackground := True;
  FIsShowLineWeight := True;
  FShowImages := True;
  FDrawMode := dmNormal;
  FLScale := 1.0;
  FBackgroundColor := clWhite;
  FDefaultColor := clBlack;
  FMillimetres := -1;
  FIntPoints := TList.Create;
  FCounts := TList.Create;
  FColorToLineWeight := TStringList.Create;
  FIsProcessMessages := True; // process the messages
  FDrawingBox := BadRect;
  FScale := MakeFPoint(1,1,1);
  {$IFDEF sgFR}
  FStream := TMemoryStream.Create;
  {$ENDIF}
  FDimensionsVisible := True;
  FTextVisible := True;
  FBorderSize := cnstBorderSize;
  FBorderType := cnstBorderType;
  ContainerOfTextGlyphs.Reference;
  FSHXFontsProc := GetSHXFontsProc;
  FVisibleArea := Point(0, 0);
  FSelectionMatrixMode := smDisabled;
  FGetSelectionMatrixModeProc := GetSelectionMatrixProc;
  FSetSelectionMatrixModeProc := SetSelectionMatrixProc;
end;

destructor TsgDXFImage.Destroy;
begin
{$IFDEF SGDEL_4}
  SetupSnapMatrix;
{$ENDIF}
  FIntPoints.Free;
  FCounts.Free;
  FPoly.Free;
  FCanvasParams.Brush.Free;
  FCanvasParams.Font.Free;
  FCanvasParams.Pen.Free;
  FColorToLineWeight.Free;
  FConverter.Release;
  ContainerOfTextGlyphs.Release;
  if FClippingRect <> nil then
    Dispose(FClippingRect);
  {$IFDEF sgFR}
  FStream.Free;
  {$ENDIF}
  inherited Destroy;
end;

function TsgDXFImage.AbsHeight: Extended;
begin
  Result := FYMax - FYMin;
  if FClippingRect <> nil then
    Result := (FClippingRect.Bottom - FClippingRect.Top)*1.0;
end;

function TsgDXFImage.AbsWidth: Extended;
begin
  Result := FXMax - FXMin;
  if FClippingRect <> nil then
    Result := (FClippingRect.Right - FClippingRect.Left)*1.0;
end;

procedure TsgDXFImage.SetEntityVisibility(ACADFile: TObject);
begin
  if ACADFile is TsgDXFImage then
  begin
    TsgDXFImage(ACADFile).TextVisible := TextVisible;
    TsgDXFImage(ACADFile).DimensionsVisible := DimensionsVisible;
  end;
end;

procedure TsgDXFImage.AddScaledDXF(ACADFile: TObject; AName: string; APos, AScale: TFPoint;
  Rotation: Single);
begin
  SetEntityVisibility(ACADFile);
  Converter.AddXRef(ACADFile, AName, APos, AScale, Rotation);
  GetExtents;
end;

function TsgDXFImage.AddScaledDXFEx(ACADFile: TObject; AName: string; APos, AScale: TFPoint;
  Rotation: Single): TsgDXFInsert;
begin
  SetEntityVisibility(ACADFile);
  Result := Converter.AddXRefEx(ACADFile, AName, APos, AScale, Rotation, CurrentLayout);
  GetExtents;
end;

procedure TsgDXFImage.Assign(Source: TPersistent);
begin
  if Source is TsgDXFImage then
  begin
    FConverter.Release;
    FConverter := TsgDXFImage(Source).Converter;
    FConverter.Reference;
    Self.FXMin := TsgDXFImage(Source).FXMin;
    Self.FXMax := TsgDXFImage(Source).FXMax;
    Self.FYMin := TsgDXFImage(Source).FYMin;
    Self.FYMax := TsgDXFImage(Source).FYMax;
    Self.FZMin := TsgDXFImage(Source).FZMin;
    Self.FZMax := TsgDXFImage(Source).FZMax;
    Self.FCenter := TsgDXFImage(Source).FCenter;
    Self.FCharset := TsgDXFImage(Source).Charset;
    Self.FLScale := TsgDXFImage(Source).FLScale;
    Self.FColorToLineWeight.Assign(TsgDXFImage(Source).FColorToLineWeight);
    Self.FCurrentLayout := TsgDXFImage(Source).FCurrentLayout;
    Self.BackgroundColor := TsgDXFImage(Source).BackgroundColor;
    Self.DefaultColor := TsgDXFImage(Source).DefaultColor;
    Self.DimensionsVisible := TsgDXFImage(Source).DimensionsVisible;
    Self.DrawingBox := TsgDXFImage(Source).DrawingBox;
    Self.DrawMode := TsgDXFImage(Source).DrawMode;
    Self.SetClippingRect(TsgDXFImage(Source).FClippingRect);
    Self.TextVisible := TsgDXFImage(Source).TextVisible;
    Self.UseWinEllipse := TsgDXFImage(Source).UseWinEllipse;
    Self.BorderSize := TsgDXFImage(Source).BorderSize;
    Self.BorderType := TsgDXFImage(Source).BorderType;
    Self.IsWithoutBorder := TsgDXFImage(Source).IsWithoutBorder;
    {$IFDEF sgFR}
    Self.FStream.Clear;
    Self.FStream.CopyFrom(TsgDXFImage(Source).Stream, TsgDXFImage(Source).Stream.Size);
    Self.FStream.Position := 0;
    {$ENDIF}
    ResetExtents;
    Changed(Self);
  end
  else
    inherited Assign(Source);
end;

function TsgDXFImage.GetIsDrawingRotated: Boolean;
  function IsMatrixRotated(const M: TFMatrix): Boolean;
  var
    I, J: Integer;
  begin
    for I := 0 to 2 do
      for J := 0 to 2 do
      begin
        Result := Abs(M[I,J]-Ord(I=J)) > fAccuracy;// if I=J, then M[I,J]<>1
        if Result then
          Exit;
      end;
  end;
begin
  Result := IsMatrixRotated(FCurrentLayout.RotMatrix)
    or IsMatrixRotated(FConverter.ViewTwistMatrix);
end;

procedure TsgDXFImage.ExportToMetafile(const FileName: string;
  AWidth, AHeight: Integer);
var
  MF: TMetafile;
  MC: TMetafileCanvas;
  vDc: HDC;
  mmToPixelX, mmToPixelY: Double;
begin
  if AWidth > 3276700 then
    AWidth := 3276700;
  if AHeight > 3276700 then
    AHeight := 3276700;
  vDc := GetDc(0);
  try
    mmToPixelX := GetDeviceCaps(vDc, HORZSIZE) /
      GetDeviceCaps(vDc,HORZRES);
    mmToPixelY := GetDeviceCaps(vDc, VERTSIZE) /
      GetDeviceCaps(vDc,VERTRES);
  finally
    ReleaseDC(0, vDc);
  end;
  MF := TMetafile.Create;
  try
    MF.MMWidth := AWidth;
    MF.MMHeight := AHeight;
    MC := TMetafileCanvas.Create(MF, 0);
    try
      FConverting := True;
      Draw(MC, Rect(0, 0, round(AWidth / (100 * mmToPixelX)),
                          round(AHeight / (100 * mmToPixelY))));
    finally
      FConverting := False;
      MC.Free;
    end;
    MF.SaveToFile(FileName);
  finally
    MF.Free;
  end;
end;

procedure TsgDXFImage.SetClippingRect(Value: PFRect);
begin
  if FClippingRect = nil then
    New(FClippingRect);
  if Value = nil then
  begin
    Dispose(FClippingRect);
    FClippingRect := nil;
  end
  else
    FClippingRect^ := Value^;
  Changed(Self);
end;

{$IFDEF SGDEL_4}
function TsgDXFImage.ExportToMetafile(AWidth, AHeight: Integer): TMetafile;
var
  MF: TMetafile;
  MC: TMetafileCanvas;
  mmToPixelX: Double;
  mmToPixelY, Ratio: Double;
  vMax: Integer;
  vDc: HDC;
begin
   vMax := 3276500;
   vDc := GetDc(0);
   try
     mmToPixelX := GetDeviceCaps(vDc, HORZSIZE) /
       GetDeviceCaps(vDc,HORZRES);
     mmToPixelY := GetDeviceCaps(vDc, VERTSIZE) /
       GetDeviceCaps(vDc,VERTRES);
   finally
     ReleaseDC(0, vDc);
   end;
   if AHeight <> 0 then
     Ratio := AWidth / AHeight
   else
     Ratio := 1;
   if mmToPixelX <= mmToPixelY then
     vMax := Round(vMax * mmToPixelX)
   else
     vMax := Round(vMax * mmToPixelY);
   if (AWidth > vMax) or (AHeight > vMax) then
     if Ratio <= 1 then
     begin
       AHeight := vMax;
       AWidth := Round(vMax * Ratio);
     end
     else
     begin
       AWidth := vMax;
       AHeight := Round(vMax / Ratio);
     end;

   MF := TMetafile.Create;
   MF.MMWidth := AWidth;
   MF.MMHeight := AHeight;
   FIsShowBackground := False;
   MC := TMetafileCanvas.Create(MF, 0);
   try
     FConverting := True;
     Draw(MC, Rect(0, 0, round(AWidth / (100 * mmToPixelX)),
       round(AHeight / (100 * mmToPixelY))));
   finally
     FConverting := False;
     MC.Free;
     FIsShowBackground := True;
   end;
   result := MF;
end;

function TsgDXFImage.ExportToMetafile(MaxDim: Integer): TMetafile;
var
  AWidth, AHeight: Integer;
  Ratio: Double;
begin
   if MaxDim > 3276700 then
     MaxDim := 3276700;
   Ratio := Width / Height;
   if Ratio <= 1 then
   begin
     AHeight := MaxDim;
     AWidth := round(MaxDim * Ratio);
   end
   else
   begin
     AWidth := MaxDim;
     AHeight := round(MaxDim / Ratio);
   end;
   Result := ExportToMetafile(AWidth, AHeight);
end;

function TsgDXFImage.ExportToMetafile(var OffsetX, OffsetY, UnitSize: TsgFloat): TMetafile;
const
  iMaxMetafileSizeWin98 = 32765;
  iMaxMetafileSizeWinNT = 64000000;
var
  MF: TMetafile;
  MC: TMetafileCanvas;
  vMaxDim, vRatio, vHeight, vWidth, RatioKoef: Double;
  OSVersionInfo: TOSVersionInfo;
  vFlag1, vFlag2, vFlag3: Boolean;
  vPrevRots: TFMatrix;
  S, S1: string;
  I: Integer;
  vRealExtents: TFRect;
  vDs: Char;
begin
  FExportToDXFMode := True;
  try
    if IsBadRect(FDrawingBox) then
      vRealExtents := PureExtents
    else
      vRealExtents := FDrawingBox;
    vFlag1 := Transparent;
    vFlag2 := IsWithoutBorder;
    vFlag3 := bUseSHXFonts;
    vPrevRots := CurrentLayout.RotMatrix;
    Transparent :=  True;
    IsWithoutBorder := True;
    bUseSHXFonts := False;
    OSVersionInfo.dwOSVersionInfoSize := Sizeof(TOSVersionInfo);
    GetVersionEx(OSVersionInfo);
    (* // For future versions
    if OSVersionInfo.dwPlatformId = VER_PLATFORM_WIN32_NT then
      vMaxDim := iMaxMetafileSizeWinNT
    else
      vMaxDim := iMaxMetafileSizeWin98;*)
    vMaxDim := iMaxMetafileSizeWin98;
    vRatio := AbsWidth / AbsHeight;
    if vRatio <= 1 then
      UnitSize := AbsHeight
    else
      UnitSize := AbsWidth;
    UnitSize := UnitSize / vMaxDim;
    vDs := DecimalSeparator;
    try
      DecimalSeparator := '.';
      try
        S := FloatToStr(UnitSize);
        for I := 1 to Length(S) do
          if not (S[I] in ['0', DecimalSeparator]) then
          begin
            S1 := S1 + '1';
            Break;
          end
          else
            S1 := S1 + S[I];
      except
        S1 := '';
      end;
      UnitSize := ConvToFloatDef(S1, UnitSize) * 10;
      I := Pos('E', AnsiUpperCase(S));
      if I > 0 then
        UnitSize := UnitSize * Power(10, StrToIntDef(Copy(S, I+1, MaxInt), 1));
    finally
      DecimalSeparator := vDs;
    end;
    RatioKoef := 1 / UnitSize;
    if vRatio <= 1 then
    begin
      vHeight := RatioKoef * AbsHeight;
      vWidth := vHeight * vRatio;
    end
    else
    begin
      vWidth := RatioKoef * AbsWidth;
      vHeight := vWidth / vRatio;
    end;
    MF := TMetafile.Create;
    OffsetX := Round(RatioKoef * vRealExtents.Left);
    OffsetY := Round(RatioKoef * vRealExtents.Top);
    FIsShowBackground := False;
    MC := TMetafileCanvas.Create(MF, 0);
    try
      FConverting := True;
      Draw(MC, Rect(0, 0, Round(vWidth), Round(vHeight)));
    finally
      FConverting := False;
      MC.Free;
      FIsShowBackground := True;
      Transparent := vFlag1;
      IsWithoutBorder := vFlag2;
      bUseSHXFonts := vFlag3;
      CurrentLayout.SetRotMatrix(vPrevRots);
      GetExtents;
    end;
    Result := MF;
  finally
    FExportToDXFMode := False;
  end;
end;
{$ENDIF}

function TsgDXFImage.GetPoint(const P: TFPoint): TPoint;
var
  R: TsgFloat;
begin
  R := P.X * FDraw.Matrix[0, 0] + P.Y * FDraw.Matrix[1, 0] +
    P.Z * FDraw.Matrix[2, 0] + FDraw.Matrix[3, 0];
  if Abs(R) < MaxInt then
    Result.X := Round(R)
  else
    Result.X := MaxInt;

  R := P.X * FDraw.Matrix[0, 1] + P.Y * FDraw.Matrix[1, 1] +
    P.Z * FDraw.Matrix[2, 1] + FDraw.Matrix[3, 1];
  if Abs(R) < MaxInt then
    Result.Y := Round(R)
  else
    Result.Y := MaxInt;
end;

function TsgDXFImage.GetFPoint(const P: TFPoint): TFPoint;
begin
  Result.X := P.X * FDraw.Matrix[0, 0] + P.Y * FDraw.Matrix[1, 0] +  P.Z * FDraw.Matrix[2, 0] + FDraw.Matrix[3, 0];
  Result.Y := P.X * FDraw.Matrix[0, 1] + P.Y * FDraw.Matrix[1, 1] +  P.Z * FDraw.Matrix[2, 1] + FDraw.Matrix[3, 1];
  Result.Z := P.X * FDraw.Matrix[0, 2] + P.Y * FDraw.Matrix[1, 2] +  P.Z * FDraw.Matrix[2, 2] + FDraw.Matrix[3, 2];
end;

function TsgDXFImage.GetPointUCS(P: TFPoint): TPoint;
begin
  TransformToWorldCS(P);
  Result := GetPoint(P);
end;

function TsgDXFImage.GetRealImageMatrix: TFMatrix;
begin
  if FCurrentLayout.IsModel then
    Result := MatXMat(FConverter.ViewTwistMatrix, FCurrentLayout.RotMatrix)
  else
    Result := FCurrentLayout.RotMatrix;
  // TransPoseMat(Result);// only for future versions
end;

function TsgDXFImage.GetRealImagePoint(const P: TFPoint): TFPoint;
begin
  Result := PtXMat(P, GetRealImageMatrix);
end;

function TsgDXFImage.HeadVarAsInteger(const AName: string;
  ACode: Integer): Integer;
var
  S: string;
begin
  S := FConverter.HeadVar(AName, ACode);
  if S = '' then
    Result := 1
  else
    Result := StrToInt(S);
end;

function TsgDXFImage.HeadVarAsFloat(const AName: string;
  ACode: Integer): Extended;
var
  S: string;
  DS: Char;
begin
  DS := DecimalSeparator;
  DecimalSeparator := '.';
  try
    S := FConverter.HeadVar(AName, ACode);
    if S = '' then
      Result := 0.0
    else
      Result := StrToFloat(S);
  finally
    DecimalSeparator := DS;
  end;
end;

// Access to HEADER variables in DXF
function TsgDXFImage.HeadVarAsString(const AName: string;
   ACode: Integer): string;
begin
  Result := FConverter.HeadVar(AName, ACode);
end;

procedure TsgDXFImage.LoadFromFile(const FileName: string);
var
  S: TFileStream;
  Dir: string;
begin
  Dir := GetCurrentDir;
  S := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
  try
    SetCurrentDir(ExtractFilePath(FileName));
    Converter.SHXFonts.SearchPath.Insert(0, ExtractFilePath(FileName));
    try
      {// For future versions
      OwnSource := True;
      Converter.SetSourceStream(S); }
      LoadFromStream(S)
    finally
      S.Free;
      SetCurrentDir(Dir);
    end;
  except
    OwnSource := False;
    raise;
  end;
end;

procedure TsgDXFImage.SetDefaultViewPort(AConverter: TsgDXFCOnverter);
begin
  FVPortDefault := AConverter.VPort;
  FAngleDefault := AConverter.Angle;
end;

procedure TsgDXFImage.LoadFromStream(S: TStream);
var
  R: TdxfReader;
begin
  FLScale := 0.0;
  R := TdxfReader.Create(Converter);
  Loading := Self;
  try
    FMsg := sLoadFile;     // for OnProgress
    FConverter.SetSourceStream(S);
//    FConverter.Load;
    R.Load;
    SetDefaultViewPort(Converter);
    GetExtents;
  finally
    Loading := nil;
    FFileInfo := R.FileInfo;
    R.Free;
  end;
end;

procedure TsgDXFImage.RefreshCurrentLayout;
begin
  SetExtentsParameters(FCurrentLayout.Box, FCurrentLayout.CADSpace <> csUndefined);
end;

procedure TsgDXFImage.ResetDrawingBox;
begin
  SetDrawingBox(BadRect);
end;

procedure TsgDXFImage.ResetExtents;
var
  W, H: TsgFloat;
begin
  FExtents := MakeFRect(FXMin, FYMax, FZMin, FXMax, FYMin, FZMax);
  W := AbsWidth;
  H := AbsHeight;
  if W < H then
    SwapSGFloats(W,H);
  if H = 0 then
    H := 1E-20;
  if W = 0 then
    W := 1E-20;
  if W < 10 then
    FZoom := 10
  else
  begin
    W := $7FFF / W;
    FZoom := MinDXFSize / H;
    if FZoom < 1 then
      FZoom := 1;
    if FZoom > W then
      FZoom := W;
  end;
end;

procedure TsgDXFImage.Rotate(Axis: TsgAxes; Angle: Extended);
  procedure DoMat(A, B: Integer);
  var
    M: TFMatrix;
    S, C: Extended;
  begin
    M := IdentityMat;
    SinCos(Radian(Angle), S, C);
    if Axis = axisY then
      S := -S;
    M[A, A] := C;
    M[B, B] := C;
    M[A, B] := S;
    M[B, A] := -S;
    FCurrentLayout.SetRotMatrix(MatXMat(FCurrentLayout.RotMatrix, M));
    Changed(Self);
  end;
begin
  if Abs(Angle) > MaxInt then Exit;
  if (not (Axis=axisZ) and (Angle <> 0))
    or ((Axis=axisZ) and ((Round(Abs(Angle)) mod 90) <> 0)) then
    ShowImages := False;
  case Axis of
    axisX: DoMat(1, 2);
    axisY: DoMat(0, 2);
    axisZ:
      begin
        FZRotate := FZRotate + Angle;
        DoMat(0, 1);
      end;
  end;
end;

procedure TsgDXFImage.RotDefault;
begin
  RotToView(vdDefault);
end;

procedure TsgDXFImage.RotToView(const A3DView: TsgDXFViewDirection);
begin
  if A3DView = vdDefault then
  begin
    if (FVPortDefault.X = 0) and (FVPortDefault.Y = 0) and (FVPortDefault.X = 0) then
      FVPortDefault.Z := 1;
    FConverter.VPort := FVPortDefault;
    FConverter.Angle := FAngleDefault;
    FShowImages := True;
  end
  else
  begin
    FConverter.VPort := MakeFPoint(0, 0, 1);
    FConverter.Angle := 0;
  end;
  FConverter.DoExtents;
  FCurrentLayout.SetRotMatrix(IdentityMat);
  case A3DView of
    vdDefault, vdTop:
      FZRotate := -FCurrentLayout.RotZAngle;
    vdFront:
      begin
        Rotate(AxisX, -90);
      end;
    vdBottom:
      begin
        Rotate(AxisY, 180);
      end;
    vdLeft:
      begin
        Rotate(AxisY, 90);
        Rotate(AxisZ, 90);
      end;
    vdRight:
      begin
        Rotate(AxisY, -90);
        Rotate(AxisZ, -90);
      end;
    vdBack:
      begin
        Rotate(AxisX, 90);
        Rotate(AxisZ, 180);
      end;
    vdSWIsometric:
      begin
        Rotate(AxisZ, 45);
        Rotate(AxisX, -54.735610317245345684622999669981);
      end;
    vdSEIsometric:
      begin
        Rotate(AxisZ, -45);
        Rotate(AxisX, -54.735610317245345684622999669981);
      end;
    vdNWIsometric:
      begin
        Rotate(AxisZ, 135);
        Rotate(AxisX, -54.735610317245345684622999669981);
      end;
    vdNEIsometric:
      begin
        Rotate(AxisZ, -135);
        Rotate(AxisX, -54.735610317245345684622999669981);
      end;
  end;
  RefreshCurrentLayout;
end;

procedure TsgDXFImage.SaveToFile(const FileName: string);
var
  S: TFileStream;
begin
  S := TFileStream.Create(FileName, fmCreate);
  try
    SaveToStream(S)
  finally
    S.Free
  end;
end;

procedure TsgDXFImage.SaveToStream(S: TStream);
begin
  if FConverter.Source <> nil then FConverter.Source.SaveToStream(S);
end;

procedure TsgDXFImage.SetCurrentLayout(const ALayout: TsgDXFLayout);
begin
  if Assigned(OnLayoutBeforeChange) then
    OnLayoutBeforeChange(Self);
  FCurrentLayout := ALayout;
  Converter.PaperSpace := not FCurrentLayout.IsModel;
  SetExtentsParameters(FCurrentLayout.Box, FCurrentLayout.CADSpace <> csUndefined);
  if Assigned(OnLayoutChange) then
    OnLayoutChange(Self);
end;

procedure TsgDXFImage.AssignTo(Dest: TPersistent);
begin
  if Dest is TBitmap then
    AssignToBitmap(Self, TBitmap(Dest))
  else
    if Dest is TMetafile then
      AssignToMetafile(Self, TMetafile(Dest))
    else inherited AssignTo(Dest);
end;

procedure TsgDXFImage.AddSelectionMatrix(const APointer: Pointer);
begin
  if (FDraw.Insert = nil) or (FOnInsertMode and (FDraw.Insert = FOnInsert)) then
    SelectionMatrix.AddElement(APointer)
  else
    SelectionMatrix.AddElement(nil);
end;

procedure TsgDXFImage.ClearMatrices(const ARect: TRect);
var
  Y, Y1, Y2, X, X1, X2: Integer;
begin
  SelectionMatrix.ClearRect(ARect);
{$IFDEF SGDEL_4}
  if Length(FSnapMatrix) > 0 then
  begin
    Y1 := Low(FSnapMatrix);
    Y2 := High(FSnapMatrix);
    for Y := Y1 to Y2 do
    begin
      if (Y >= ARect.Top) and (Y <= ARect.Bottom) then
      begin
        X1 := Low(FSnapMatrix[Y]);
        X2 := High(FSnapMatrix[Y]);
        for X := X1 to X2 do
        begin
          if (X >= ARect.Left) and (X <= ARect.Right) and Assigned(FSnapMatrix[Y, X]) then
          begin
            Dispose(FSnapMatrix[Y, X]);
            FSnapMatrix[Y, X] := nil;
          end;
        end;
      end;
    end;
  end;
{$ENDIF}
end;

function TsgDXFImage.CreateConverter: TsgDXFConverter;
begin
  Result := TsgDXFConverter.Create('');
end;

procedure TsgDXFImage.Draw3DAxes;
var
  PtCntr: TPoint;
  vSize: Single;

  procedure DrawAxis(const AName: string; AAxis: TFPoint; AColor: TColor);
  var
    vPtAxis: TPoint;
  begin
    FCanvas.Pen.Color := AColor;
    FCanvas.Font.Color := FCanvas.Pen.Color;
    FCanvas.MoveTo(PtCntr.X, PtCntr.Y);
    vPtAxis := GetPoint(MakeFPoint(FCenter.X + AAxis.X,
      FCenter.Y + AAxis.Y, FCenter.Z + AAxis.Z));
    FCanvas.LineTo(vPtAxis.X, vPtAxis.Y);
    FCanvas.TextOut(vPtAxis.X, vPtAxis.Y, AName);
  end;
begin
  vSize := AbsWidth;
  if vSize > AbsHeight then
    vSize := AbsHeight;
  vSize := vSize / 4;
  if vSize <= 0 then
    vSize := 1;
  PtCntr := GetPoint(FCenter);
  FCanvas.Pen.Width := 2;

  DrawAxis('X', MakeFPoint(vSize,0,0), clRed);// FNew0X
  DrawAxis('Y', MakeFPoint(0,vSize,0), TColor(RGB(68, 235, 140)));//FNew0Y
  DrawAxis('Z', MakeFPoint(0,0,vSize), clBlue);// FNew0Z
  FCanvas.Font.Size := 6;
  FCanvas.Pen.Color := clAqua;
  FCanvas.Ellipse(PtCntr.X - 1, PtCntr.Y - 1, PtCntr.X + 1, PtCntr.Y + 1);
end;

function TsgDXFImage.CoordinateBorderCorrect(var AXScaled, AYScaled: Extended): Boolean;
var
  vTemp: TsgFloat;
  vBorderRatio, vCorrectedBorderRatio: TsgFloat;
begin
  Result := True;
  if IsWithoutBorder then
  begin
    AXScaled := AXScaled;
    AYScaled := AYScaled;
  end
  else
    if BorderType = btRatio then
  begin
    vCorrectedBorderRatio := BorderSize + FXDisproportionateShift;
    AXScaled := AXScaled * (1 + 2 * vCorrectedBorderRatio) - vCorrectedBorderRatio;
    vCorrectedBorderRatio := BorderSize + FYDisproportionateShift;
    AYScaled := AYScaled * (1 + 2 * vCorrectedBorderRatio) - vCorrectedBorderRatio;
  end
  else
    if BorderType = btGlobal then
  begin
    vTemp := FExtents.Right - FExtents.Left - 2 * BorderSize;
    if vTemp <> 0 then
      vBorderRatio := BorderSize / vTemp
    else
    begin
      Result := False;
      Exit;
    end;
    vCorrectedBorderRatio := vBorderRatio + FXDisproportionateShift;
    AXScaled := AXScaled * (1 + 2 * vCorrectedBorderRatio) - vCorrectedBorderRatio;
    vTemp := FExtents.Top - FExtents.Bottom - 2 * BorderSize;
    if vTemp <> 0 then
      vBorderRatio := BorderSize / vTemp
    else
    begin
      Result := False;
      Exit;
    end;
    vCorrectedBorderRatio := vBorderRatio + FYDisproportionateShift;
    AYScaled := AYScaled * (1 + 2 * vCorrectedBorderRatio) - vCorrectedBorderRatio;
  end
  else
    Result := False;
end;

procedure TsgDXFImage.FillBoxForCoordsCalc(ACoord: Integer; var ABox: TFRect);
begin
  case ACoord of
    1:
    begin
      ABox.Left := FCurrentLayout.Box.Z1;
      ABox.Right := FCurrentLayout.Box.Z2;
      ABox.Bottom := FCurrentLayout.Box.Bottom;
      ABox.Top := FCurrentLayout.Box.Top;
      ABox.Z1 := FCurrentLayout.Box.Left;
      ABox.Z2 := FCurrentLayout.Box.Right;
    end;
    2:
    begin
      ABox.Left := FCurrentLayout.Box.Left;
      ABox.Right := FCurrentLayout.Box.Right;
      ABox.Bottom := FCurrentLayout.Box.Z1;
      ABox.Top := FCurrentLayout.Box.Z2;
      ABox.Z1 := FCurrentLayout.Box.Bottom;
      ABox.Z2 := FCurrentLayout.Box.Top;
    end;
  else
    ABox.Left := FCurrentLayout.Box.Left;
    ABox.Right := FCurrentLayout.Box.Right;
    ABox.Bottom := FCurrentLayout.Box.Bottom;
    ABox.Top := FCurrentLayout.Box.Top;
    ABox.Z1 := FCurrentLayout.Box.Z1;
    ABox.Z2 := FCurrentLayout.Box.Z2;
  end;
end;

function TsgDXFImage.IsDrawOnBitMap: Boolean;
begin
  Result := (not Converter.ViewPortCut) and ((GetMatrixMode <> smDisabled) or FOnInsertMode);
end;

function TsgDXFImage.IsDrawOnCanvas: Boolean;
begin
  Result := GetMatrixMode <> smMatrixOnly;
end;

function TsgDXFImage.CalcCADCoordsParameters({AXScaled, AYScaled: Extended;
         var AX, AY: TsgFloat; var ARot: TFMatrix;
         var ARealLayoutCenter: TFPoint; var ANullCoord: Integer}var AStruct: TsgCalcCoordsStruct): Boolean;
var
  vWidth, vHeight, vZWidth, vZHeight, vZXShift, vZYShift: TsgFloat;
  vRot: TFMatrix;
  vBox: TFRect;
  vXScaledCorrect, vYScaledCorrect: Extended;

  procedure AssignCoords(I: Integer);
  var
    M: TFMatrix;
  begin
    AStruct.NullCoord := I;
    M := GetRealImageMatrix;
    FillBoxForCoordsCalc(I, vBox);
    case I of
      1:
      begin
        vRot[0, 0] := M[2, 0];
        vRot[1, 1] := M[1, 1];
        vRot[2, 2] := 0;
        vRot[0, 1] := M[2, 1];
        vRot[0, 2] := 0;
        vRot[1, 0] := M[1, 0];
        vRot[1, 2] := 0;
        vRot[2, 0] := 0;
        vRot[2, 1] := 0;
      end;
      2:
      begin
        vRot[0, 0] := M[0, 0];
        vRot[1, 1] := M[2, 1];
        vRot[2, 2] := 0;
        vRot[0, 1] := M[0, 1];
        vRot[0, 2] := 0;
        vRot[1, 0] := M[2, 0];
        vRot[1, 2] := 0;
        vRot[2, 0] := 0;
        vRot[2, 1] := 0;
      end;
    else
      vRot := M;
    end;
    vWidth := Abs((vBox.Right - vBox.Left) * vRot[0, 0]) + Abs((vBox.Top - vBox.Bottom) * vRot[1, 0]);
    vHeight := Abs((vBox.Top - vBox.Bottom) * vRot[1, 1]) + Abs((vBox.Right - vBox.Left) * vRot[0, 1]);
  end;

begin
  Result := True;
  if IsBadRect(FCurrentLayout.Box) then
  begin
    Result := False;
    Exit;
  end;

  vXScaledCorrect := AStruct.XScaled;
  vYScaledCorrect := AStruct.YScaled;
  if not CoordinateBorderCorrect(vXScaledCorrect, vYScaledCorrect) then
  begin
    Result := False;
    Exit;
  end;

  AssignCoords(0);
  if Abs(Abs(vRot[1, 2]) - 1) < fAccuracy then
    AssignCoords(2)
  else
    if Abs(Abs(vRot[0, 2]) - 1) < fAccuracy then
    AssignCoords(1);
  if (vWidth = 0) or (vHeight = 0) then
  begin
    Result := False;
    Exit;
  end;

  vZWidth := Abs((vBox.Z2 - vBox.Z1) * vRot[2, 0]);
  vZHeight := Abs((vBox.Z2 - vBox.Z1) * vRot[2, 1]);
  vZXShift := vBox.Z1 * vRot[2, 0] / (vZWidth + vWidth);
  vZYShift := vBox.Z1 * vRot[2, 1] / (vZHeight + vHeight);
  AStruct.RealLayoutCenter.X := 0.5 * (vBox.Right + vBox.Left);
  AStruct.RealLayoutCenter.Y := 0.5 * (vBox.Top + vBox.Bottom);
  AStruct.RealLayoutCenter.Z := 0.0;

  if vRot[2, 0] > 0 then
    AStruct.X := vWidth * ((vXScaledCorrect + vZXShift) * (vZWidth + vWidth) / vWidth - 0.5)
  else
    AStruct.X := vWidth * ((vXScaledCorrect - vZWidth / (vZWidth + vWidth) + vZXShift) * (vZWidth + vWidth) / vWidth - 0.5);
  if vRot[2, 1] > 0 then
    AStruct.Y := vHeight * ((vYScaledCorrect + vZYShift) * (vZHeight + vHeight) / vHeight - 0.5)
  else
    AStruct.Y := vHeight * ((vYScaledCorrect - vZHeight / (vZHeight + vHeight) + vZYShift) * (vZHeight + vHeight) / vHeight - 0.5);
  AStruct.Rot := vRot;
end;

function TsgDXFImage.GetCADCoords(const AXScaled, AYScaled: Extended): TFPoint;
var
  C, N, A, B, ASubB, Intersect{, vRealLayoutCenter}: TFPoint;
  T, NMulC: TsgFloat;
  //vRot: TFMatrix;
  //vX, vY: TsgFloat;
  SubResult: TFPoint;
  //vNullCoord: Integer;
  vStruct: TsgCalcCoordsStruct;

  function VecXVec(V1, V2: TFPoint): TsgFloat;
  begin
    Result := V1.X * V2.X + V1.Y * V2.Y + V1.Z * V2.Z;
  end;

  procedure Transpose(var A: TFMatrix);
  begin
    SwapSGFloats(A[0,1], A[1,0]);
    SwapSGFloats(A[0,2], A[2,0]);
    SwapSGFloats(A[2,1], A[1,2]);
  end;

begin
  vStruct.XScaled := AXScaled;
  vStruct.YScaled := AYScaled;
  if not CalcCADCoordsParameters(vStruct) then
  begin
    Result := MakeFPoint(0, 0, 0);
    Exit;
  end;

  C := MakeFPoint(0.0, 0.0, -1.0);
  N := PtXMat(MakeFPoint(0.0, 0.0, 1.0), vStruct.Rot);
  A := MakeFPoint(vStruct.X, vStruct.Y, 0.0);
  B := MakeFPoint(0.0, 0.0, 0.0);
  ASubB := MakeFPoint(B.X - A.X, B.Y - A.Y, B.Z - A.Z);
  NMulC := VecXVec(N, C);
  if NMulC <> 0 then //It is always not null
    T := VecXVec(N, ASubB) / NMulC
  else
    T := 0;
  Intersect := MakeFPoint(A.X + C.X * T, A.Y + C.Y * T, A.Z + C.Z * T);
  Transpose(vStruct.Rot);
  SubResult := PtXMat(Intersect, vStruct.Rot);
  case vStruct.NullCoord of
    1:
    begin
      Result.X := 0;
      Result.Y := SubResult.Y + vStruct.RealLayoutCenter.Y;
      Result.Z := SubResult.X + vStruct.RealLayoutCenter.X;
    end;
    2:
    begin
      Result.X := SubResult.X + vStruct.RealLayoutCenter.X;
      Result.Y := 0;
      Result.Z := SubResult.Y + vStruct.RealLayoutCenter.Y;
    end;
  else
    Result.X := SubResult.X + vStruct.RealLayoutCenter.X;
    Result.Y := SubResult.Y + vStruct.RealLayoutCenter.Y;
    Result.Z := 0;
  end;
end;

{$IFDEF SGDEL_4}
function TsgDXFImage.GetCADCoords(const AXScaled, AYScaled: Extended;
  var CoordsInUCS: TFPoint): TFPoint;
begin
  Result := GetCADCoords(AXScaled, AYScaled);
  CoordsInUCS := Result;
  TransformToUCS(CoordsInUCS);
end;
{$ENDIF}

{$IFDEF SGDEL_4}
function TsgDXFImage.GetSnapData(const P: TPoint): PSnapData;
begin
  if IsIndexInArray(P) then
    Result := PSnapData(FSnapMatrix[P.Y - 1, P.X - 1])
  else
    Result := nil;
end;

function TsgDXFImage.GetObjectSnapMode: TObjectSnapMode;
begin
  Result := FObjectSnapMode;
end;

procedure TsgDXFImage.SetObjectSnapMode(AValue: TObjectSnapMode);
var
  B: Boolean;
begin
  if (FObjectSnapMode = osDisabled) or (AValue = osDisabled) then
  begin
    FObjectSnapMode := AValue;
    Exit;
  end;
  FObjectSnapMode := AValue;
  SetupSnapMatrix;
  if AValue <> osNone then
  begin
    if Converter.Params <> nil then
    begin
      FSnapOnlyIterate := True;
      B := Converter.AutoInsert;
      try
        Converter.AutoInsert := (FObjectSnapMode = osAll);
        FCurrentLayout.Iterate(Converter, DrawEntity, DoFinish);
      finally
        Converter.AutoInsert := B;
        FSnapOnlyIterate := False;
      end;
    end;
  end;
end;

procedure TsgDXFImage.SetupSnapMatrix;
var
  I, J, L, H, L1, H1: Integer;
begin
  if (FObjectSnapMode = osNone) and (Length(FSnapMatrix) = 0) then
  begin
    FObjectSnapMode := osNone;
    Exit;
  end;
  L := Low(FSnapMatrix);
  H := High(FSnapMatrix);
  for I := L to H do
  begin
    L1 := Low(FSnapMatrix[I]);
    H1 := High(FSnapMatrix[I]);
    for J := L1 to H1 do
      if Assigned(FSnapMatrix[I, J]) then
      begin
        Dispose(FSnapMatrix[I, J]);
        FSnapMatrix[I, J] := nil;
      end;
  end;
  if FVisibleArea.X <> 0 then
    sgVisibleArea := FVisibleArea;
  SetLength(FSnapMatrix, sgVisibleArea.Y);
  for I := Low(FSnapMatrix) to High(FSnapMatrix) do
    SetLength(FSnapMatrix[I], sgVisibleArea.X);
end;

function TsgDXFImage.IsIndexInArray(Pt: TPoint): Boolean;
var
  L, H: Integer;
begin
  Result := True;
  if (Pt.Y - 1 < Low(FSnapMatrix)) or (Pt.Y - 1 > High(FSnapMatrix)) then
  begin
    Result := False;
    Exit;
  end;
  L := Low(FSnapMatrix[Pt.Y - 1]);
  H := High(FSnapMatrix[Pt.Y - 1]);
  if (Pt.X - 1 < L) or (Pt.X - 1 > H) then
    Result := False;
end;

procedure TsgDXFImage.SetPixelSnap(APt: TFPoint);
var
  FSnapMatrixElement: PSnapData;
  Pt: TPoint;
  vAbsolutePt: TFPoint;
  //P: Pointer;
begin
  Pt := GetPoint(APt);
  if sgClientRectForSnap.Left <> MaxInt then
    Pt.X := Pt.X - sgClientRectForSnap.Left;
  if sgClientRectForSnap.Top <> MaxInt then
    Pt.Y := Pt.Y - sgClientRectForSnap.Top;
  if not IsIndexInArray(Pt) then Exit;
  New(FSnapMatrixElement);
  vAbsolutePt := PtXMat(APt, Converter.GetTransform3D);
  FSnapMatrixElement.Entity := FSnapEntity;
  FSnapMatrixElement.SnapMode := FCurrSnapMode;
  FSnapMatrixElement.IsSnapPoint := True;
  FSnapMatrixElement.CADPoint := vAbsolutePt;
  TransformToUCS(vAbsolutePt);
  FSnapMatrixElement.CADPointInUCS := vAbsolutePt;
  {P := @FSnapMatrix[Pt.Y - 1, Pt.X - 1];
  if Pointer(P^) <> nil then
    Dispose(Pointer(P^));
  Pointer(P^) := FSnapMatrixElement;}
  if FSnapMatrix[Pt.Y - 1, Pt.X - 1] <> nil then
    Dispose(FSnapMatrix[Pt.Y - 1, Pt.X - 1]);
  FSnapMatrix[Pt.Y - 1, Pt.X - 1] := FSnapMatrixElement;
end;
{$ENDIF}

procedure TsgDXFImage.SetClip(AInsert: TsgCADClipInsert);
var
  H: HRgn;
  F: TFRect;
  R: array[0..3] of TPoint;
  vIsDrawOnBitMap, vIsDrawOnCanvas: Boolean;

  function GetRgnPoint(X, Y, DX, DY: TsgFloat): TPoint;
  var
    P: TPoint;
  begin
    Result := GetPoint(MakeFPoint(X, Y, 0));
    while True do
    begin
      P := GetPoint(MakeFPoint(X+DX,Y+DY,0));
      if (P.X <> Result.X) and (P.Y <> Result.Y) then Break;
      DX := DX * 2;
      DY := DY * 2;
    end;
    if P.X > Result.X then
      Inc(Result.X)
    else
      Dec(Result.X);
    if P.Y > Result.Y then
      Inc(Result.Y)
    else
      Dec(Result.Y);
  end;
begin
  vIsDrawOnBitMap := IsDrawOnBitMap;
  vIsDrawOnCanvas := IsDrawOnCanvas;
  if not (vIsDrawOnBitMap or vIsDrawOnCanvas) then Exit;
  F := AInsert.Box;
  if IsBadRect(F) then Exit;
  R[0] := GetRgnPoint(F.Left, F.Top, -1, 1);
  R[1] := GetRgnPoint(F.Right, F.Top, 1, 1);
  R[2] := GetRgnPoint(F.Right, F.Bottom, 1, -1);
  R[3] := GetRgnPoint(F.Left, F.Bottom, -1, -1);
  H := CreatePolygonRgn(R, 4, WINDING);
  R[0] := Point(0,0);
  LPtoDP(FCanvas.Handle, R, 1);
  OffsetRgn(H, R[0].X, R[0].Y);
  if FClipRegion <> 0 then CombineRgn(H, H, FClipRegion, RGN_AND);
  if vIsDrawOnBitMap then
    SelectClipRgn(SelectionMatrix.Canvas.Handle, H);
  if vIsDrawOnCanvas then
    SelectClipRgn(FCanvas.Handle, H);
  DeleteObject(H);
end;

procedure TsgDXFImage.Draw(Canvas: TCanvas; const Rect: TRect);
var
  vRectWidth, vRectHeight, vPrevMode: Integer;
  OldPal: HPalette;
  vRect, vDB: TRect;
  K: Double;
  vSelectionMatrixMode: TsgSelectionMode;
  vHRGN: HRGN;
begin
{$IFDEF SGDEL_4}
  SetupSnapMatrix;
{$ENDIF}
  vSelectionMatrixMode := GetMatrixMode;
  if (vSelectionMatrixMode <> smDisabled) or (FOnInsert <> nil) then
    SelectionMatrix.Size := FVisibleArea
  else
    SelectionMatrix.Size := Point(1, 1);
  vRect := Rect;
  if FClippingRect <> nil then
  begin
    vRectWidth := vRect.Right - vRect.Left;
    K := 1;
    if FClippingRect^.Right - FClippingRect^.Left <> 0 then
      K := vRectWidth / (FClippingRect^.Right - FClippingRect^.Left);
    vRect.Left := vRect.Left - Round(FClippingRect^.Left * K);
    if FClippingRect^.Right - FClippingRect^.Left <> 0 then
      K := (Extents.Right - Extents.Left) / (FClippingRect^.Right - FClippingRect^.Left);
    vRect.Right := vRect.Left + Round(vRectWidth * K);
    vRectHeight := vRect.Bottom - vRect.Top;
    if FClippingRect^.Bottom - FClippingRect^.Top <> 0 then
      K := vRectHeight / (FClippingRect^.Bottom - FClippingRect^.Top);
    vRect.Top := vRect.Top - Round(FClippingRect^.Top * K);
    if FClippingRect^.Bottom - FClippingRect^.Top <> 0 then
      K := (Extents.Top - Extents.Bottom) / Abs(FClippingRect^.Bottom - FClippingRect^.Top);
    vRect.Bottom := vRect.Top + Round(vRectHeight * K);
  end;
  Drawing := Self;
  FCanvas := Canvas;
  try
    ApplyScale(vRect.Right - vRect.Left, vRect.Bottom - vRect.Top)
  except
    Exit
  end;
  vPrevMode := SetGraphicsMode(FCanvas.Handle, GM_COMPATIBLE);// GM_ADVANCED
  FDX := FDX + vRect.Left;
  FDY := FDY + vRect.Top;
  FDraw.Additional := Ord(IsRotated(FDraw.Matrix));
  FDraw.Matrix[3, 0] := FDraw.Matrix[3, 0] + FDX;
  FDraw.Matrix[3, 1] := FDraw.Matrix[3, 1] + FDY;
  OldPal := SelectPalette(FCanvas.Handle, AcadPal, True);
  FmmToPixelX := GetDeviceCaps(FCanvas.Handle, HORZSIZE) / GetDeviceCaps(FCanvas.Handle, HORZRES);
  FCanvasParams.Brush.Assign(Canvas.Brush);
  FCanvasParams.Font.Assign(Canvas.Font);
  FCanvasParams.Pen.Assign(Canvas.Pen);
  vHRGN := CreateRectRgn(0, 0, 0, 0);
  if GetClipRgn(FCanvas.Handle, vHRGN) <= 0 then
  begin
    DeleteObject(vHRGN);
    vHRGN := 0;
  end;
  FClipRegion := vHRGN;
  try
    RealizePalette(FCanvas.Handle);
    if not Transparent then
    begin
      Canvas.Brush.Style := bsSolid;
      Canvas.Brush.Color := FBackgroundColor;
      if FIsShowBackground and (vSelectionMatrixMode <> smMatrixOnly) then
        Canvas.FillRect(vRect);
    end;
    // Set default GDI-ojects styles
    Canvas.Pen.Mode := pmCopy;
    Canvas.Pen.Style := psSolid;
    Canvas.Brush.Style := bsClear;
    // Set converter initial parameters
    Converter.AutoInsert := False;
//    Converter.OnInsert := EnterInsert;
//    Converter.OnViewPort := EnterViewport;
//    Converter.OnXRef := EnterXRef;
    Converter.Params := @FDraw;
    if not IsBadRect(FDrawingBox) then
    begin
      vDB := GetRect(FDrawingBox);
      InflateRect(vDB,1,1);
      IntersectClipRect(FCanvas.Handle, vDB.Left, vDB.Top, vDB.Right, vDB.Bottom);
    end;
    if FClippingRect <> nil then
      IntersectClipRect(FCanvas.Handle, Rect.Left, Rect.Top, Rect.Right, Rect.Bottom);
//    SetStretchBltMode(FCanvas.Handle, COLORONCOLOR);
    SetStretchBltMode(FCanvas.Handle, HALFTONE);
    FCurrentLayout.Iterate(Converter, DrawEntity, DoFinish);
    if FIsDraw3DAxes then
      Draw3DAxes;
  finally
    SelectClipRgn(FCanvas.Handle, vHRGN);
    if vHRGN <> 0 then
      DeleteObject(vHRGN);
    FCurrentLayout.RotZAngle := FCurrentLayout.RotZAngle+FZRotate;
    FZRotate := 0;
    SelectPalette(FCanvas.Handle, OldPal, True);
    Canvas.Brush := FCanvasParams.Brush;
    Canvas.Font := FCanvasParams.Font;
    Canvas.Pen := FCanvasParams.Pen;
    SetGraphicsMode(FCanvas.Handle, vPrevMode);
  end;
end;

function TsgDXFImage.DrawEntity(Entity: TsgDXFEntity): Integer;
var
  Cmplx: Boolean;
  W: Integer;
  vIntersectRect, vTmpIRect: TRect;
  vMatrixMode: TsgSelectionMode;

  function IsVisible: Boolean;
  var
    L: TsgDXFLayer;
  begin
    L := EntLayer(Entity, FDraw.Insert);
    Result := Entity.Visibility and (((L = nil) or L.Visible) or (Entity is TsgDXFInsert))
      and (not IsPlotting or (IsPlotting and ((L=nil) or ((L<>nil) and L.IsPlotting))));
    if (L <> nil) and (L.Frozen or L.IsFrozenByViewPort) then
      Result := False;
    if Entity is TsgDXFPoint then
      Result := Result and (FConverter.PointDisplayMode <> 1);
  end;

   function IsEntityInRectVisible(ARect: TRect): Boolean;
   begin
     if vMatrixMode = smMatrixOnly then
       Result := RectVisible(SelectionMatrix.Canvas.Handle, ARect)
     else
     begin
       Result := RectVisible(FCanvas.Handle, ARect) or
         (IsDrawOnBitMap and RectVisible(SelectionMatrix.Canvas.Handle, ARect));
     end;
   end;

begin
  Result := 0;
  vMatrixMode := GetMatrixMode;
  try
    Cmplx := IsVisible;
    if Entity is TsgDXFViewPort then
    begin
      TsgDXFViewPort(Entity).VisibleBoundary := Cmplx;
      FCanvas.Pen.Color := GetEntityColor(Entity, FDraw.Insert);
      if (FCanvas.Pen.Color = clNone) or (DrawMode = dmBlack) then
        FCanvas.Pen.Color := FDefaultColor;
      Result := DoDraw(Entity);// allways call draw function for TsgDXFVewport
    end
    else
    begin
//      if Entity is TsgDXFImageEnt then
//        TsgDXFImageEnt(Entity).Rotate := TsgDXFImageEnt(Entity).Rotate + FZRotate;
      if not Cmplx then
        Exit;
  {$IFDEF SGDEL_4}
      DrawEntityOnSnapMatrix(Entity);
      if FSnapOnlyIterate then
        Exit;
  {$ENDIF}
      Cmplx := Entity is TsgDXFAttdef;
      FReady := False;
      if not Cmplx then      // checks if drawing is needed
      begin
        FIRect := cnstBad2DRect;
        FIndex := 0;
        FReady := Entity.GetBoxPoints(BoxPoint, FDraw.Additional <> 0);
        vTmpIRect := FIRect;
        Inc(vTmpIRect.Right);
        Inc(vTmpIRect.Bottom);
        W := Ceil(GetLineScale * EntLineWeight(Entity, FDraw.Insert) * 0.5 / FmmToPixelX);
        InflateRect(vTmpIRect,W,W);
      end;
  {$IFDEF SGDEL_4}
      if not Cmplx and (FObjectSnapMode <> osNone) and (Entity is TsgDXFInsert) then
      begin
        IntersectRect(vIntersectRect, sgClientRectForSnap, vTmpIRect);
        if (not IsRectEmpty(vIntersectRect)) and (not RectVisible(FCanvas.Handle, vTmpIRect)) then
        begin
          if FStoreInsert = nil then
          begin
            FStoreSnapOnlyIterate := FSnapOnlyIterate;
            FSnapOnlyIterate := True;
            FStoreInsert := FDraw.Insert;
          end;
          DoDraw(Entity);
          if FStoreInsert = FDraw.Insert then
          begin
            FSnapOnlyIterate := FStoreSnapOnlyIterate;
            FStoreInsert := nil;
          end;
        end;
      end;
  {$ENDIF}
      if Cmplx or (FCanvas is TMetafileCanvas) or IsEntityInRectVisible(vTmpIRect) then
      begin
        FCanvas.Pen.Color := GetEntityColor(Entity, FDraw.Insert);
        if (FCanvas.Pen.Color = clNone) or (DrawMode = dmBlack) then
          FCanvas.Pen.Color := FDefaultColor;
        if (Entity is TsgDXFText) or (Entity is TsgDXFMText) then
          FCanvas.Font.Color := FCanvas.Pen.Color;
        Result := DoDraw(Entity);
      end;
    end;
  finally
    SetMatrixMode(vMatrixMode);
  end;
end;

{$IFDEF SGDEL_4}
procedure TsgDXFImage.DrawEntityOnSnapMatrix(Entity: TsgDXFEntity);
var
  vPt: TFPoint;

  procedure PolylinePoints(APolyLine: TsgDXFPolyline);
  var
    I: Integer;
  begin
    if APolyLine.PolyPoints.Count > 0 then
    begin
      FCurrSnapMode := osEndPt;
      for I := 0 to APolyLine.PolyPoints.Count - 1 do
        SetPixelSnap(PFPoint(APolyLine.PolyPoints.Items[I])^);
    end;
  end;

  procedure FlatpolyPoints(APoly: TsgFlatPoly);
  var
    I: Integer;
  begin
    if APoly.PCount > 0 then
    begin
      FCurrSnapMode := osEndPt;
      for I := 0 to APoly.PCount - 1 do
        SetPixelSnap(APoly.XY[I]);
    end;
  end;

begin
  if FObjectSnapMode in [osNone, osDisabled] then Exit;
  FSnapEntity := Entity;
  if FObjectSnapMode = osInsert then
  begin
    if (FSnapEntity is TsgDXFInsert) and (FDraw.Insert = nil) then
    begin
      FCurrSnapMode := osInsert;
      if FSnapEntity is TsgDXFDimension then
        SetPixelSnap(TsgDXFDimension(FSnapEntity).DefPoint)
      else
        if FSnapEntity is TsgDXFMTExt then
          SetPixelSnap(TsgDXFMTExt(FSnapEntity).Point)
        else
          SetPixelSnap(TsgDXFInsert(FSnapEntity).Point);
    end;

    (*if FDraw.Insert <> nil then
      if FDraw.Insert is TsgDXFInsert then
      begin
        FCurrSnapMode := osInsert;
        if FDraw.Insert is TsgDXFDimension then
          SetPixelSnap(TsgDXFDimension(FDraw.Insert).DefPoint)
        else
          if FDraw.Insert is TsgDXFMTExt then
          SetPixelSnap(TsgDXFInsert(FDraw.Insert).Point)
        else
          SetPixelSnap(TsgDXFInsert(FDraw.Insert).Point{MakeFPoint(0,0,0)});
      end;*)
  end
    else
  if Entity is TsgDXFLine then
  begin
    FCurrSnapMode := osEndPt;
    SetPixelSnap({PtXMat(}TsgDXFLine(Entity).Point{, @M});
    SetPixelSnap({PtXMat(}TsgDXFLine(Entity).Point1{, @M});
    if Entity is TsgDXFSolid then
    begin
      SetPixelSnap(TsgDXFSolid(Entity).Point2);
      SetPixelSnap(TsgDXFSolid(Entity).Point3);
    end;
  end
  else
    if Entity is TsgDXFCircle then
    begin
      FCurrSnapMode := osCenter;
      if Entity is TsgDXFEllipse then
      begin
        vPt := {DoTransform}(TsgDXFEllipse(Entity).Point);
        DoExtrusion(vPt, TsgDXFEllipse(Entity).Extrusion);
        SetPixelSnap(vPt);
        if not(Abs(TsgDXFEllipse(Entity).StartAngle - TsgDXFEllipse(Entity).EndAngle + 360) < FAccuracy)and
          (TsgDXFEllipse(Entity).PolyPoints <> nil) then
        begin
          vPt := TsgDXFEllipse(Entity).Points[0];
          FCurrSnapMode := osEndPt;
          SetPixelSnap(vPt);
          vPt := TsgDXFEllipse(Entity).Points[TsgDXFEllipse(Entity).PolyPoints.Count - 1];
          SetPixelSnap(vPt);
        end;
      end
      else
        if Entity is TsgDXFArc then
      begin
        SetPixelSnap(TsgDXFCircle(Entity).Point);
        FCurrSnapMode := osEndPt;
        SetPixelSnap(TsgDXFArc(Entity).StartPoint);
        SetPixelSnap(TsgDXFArc(Entity).EndPoint);
        {vPolyLine := TsgDXFPolyline(Entity);
        if vPolyLine.PolyPoints.Count > 0 then
        begin
          DoSubSearch(PFPoint(vPolyLine.PolyPoints.First)^, Entity, osEndPt);
          DoSubSearch(PFPoint(vPolyLine.PolyPoints.Last)^, Entity, osEndPt);
        end;}
      end
      else
        SetPixelSnap(TsgDXFCircle(Entity).Point);
    end
    else
      if Entity is TsgDXFSpline then
    begin
      FCurrSnapMode := osEndPt;
      SetPixelSnap(TsgDXFSpline(Entity).Points[0]);
      SetPixelSnap(TsgDXFSpline(Entity).Points[TsgDXFEllipse(Entity).PolyPoints.Count - 1]);
    end
    else
      if Entity is TsgDXFPolyline then
        PolylinePoints(TsgDXFPolyLine(Entity))
    else
      if Entity is TsgFlatPoly then
        FlatpolyPoints(TsgFlatPoly(Entity))
    else
      if Entity is TsgDXFPoint then
        SetPixelSnap(TsgDXFPoint(Entity).Point);
end;
{$ENDIF}

procedure TsgDXFImage.DrawRect(DC: HDC; SourceRect: TFRect; DestRect: TRect);
var
  vCanvas: TCanvas;
  vBox: TFRect;
  vClip: TFRect;
begin
  if SourceRect.Left > SourceRect.Right then
    SwapSGFloats(SourceRect.Left, SourceRect.Right);
  if SourceRect.Bottom > SourceRect.Top then
    SwapSGFloats(SourceRect.Top, SourceRect.Bottom);
  if SourceRect.Z1 > SourceRect.Z2 then
    SwapSGFloats(SourceRect.Z1, SourceRect.Z2);
  vCanvas := TCanvas.Create;
  try
    vCanvas.Handle := DC;
    vBox := FDrawingBox;
    try
      vClip.Left := - Extents.Left + SourceRect.Left;
      vClip.Top := Extents.Top - SourceRect.Top;
      vClip.Right := - Extents.Left + SourceRect.Right;
      vClip.Bottom := Extents.Top - SourceRect.Bottom;
      SetClippingRect(@vClip);
      Draw(vCanvas, DestRect);
    finally
      FDrawingBox := vBox;
      SetClippingRect(nil);
    end;
  finally
    vCanvas.Free;
  end;
end;

function TsgDXFImage.GetEntityColor(AEntity: TsgDXFEntity; AInsert: TsgDXFInsert): TColor;
begin
  Result := EntColor(AEntity, AInsert);
end;

function TsgDXFImage.GetEmpty: Boolean;
begin
  Result := False;//(FConverter.Counts[csEntities] = 0);
end;

procedure TsgDXFImage.GetExtents;
const CS: array [Boolean] of TFontCharset = (DEFAULT_CHARSET, OEM_CHARSET);
begin
  FCharset := CS[FConverter.OEM];
  FConverter.DoExtents;
  if CurrentLayout = nil then
    SetCurrentLayout(FConverter.Layouts[0])
  else
    SetCurrentLayout(CurrentLayout);
end;

function TsgDXFImage.GetHeight: Integer;
begin
  Result := Round(FZoom*AbsHeight + 0.5);
  if Result = 0 then
    Result := 1;
end;

function TsgDXFImage.GetMillimetres: Boolean;
begin
  if (FMillimetres < 0) and (FConverter <> nil) then
    FMillimetres := Integer(FConverter.HeadVarStruct.Measurement);
  Result := FMillimetres <> 0;
end;

function TsgDXFImage.GetPalette: HPalette;
begin
  Result := AcadPal;
end;

function TsgDXFImage.GetWidth: Integer;
begin
  Result := Round(FZoom * AbsWidth + 0.5);
  if Result = 0 then
    Result := 1;
end;

procedure TsgDXFImage.LoadFromClipboardFormat(Fmt: Word; Data: THandle;
  Pal: HPALETTE);
var
  S: TClipboardStream;
begin
  if Fmt = CF_DXF then
    Data := GetClipboardData(CF_TEXT);
  if (Fmt <> CBFormat) or (Data = 0)
  then
    raise EInvalidGraphic.Create('Invalid DXF data');
  S := TClipboardStream.Create(Data);
  try
    LoadFromStream(S)
  finally
    S.Free
  end;
end;

procedure TsgDXFImage.Progress(Sender: TObject; Stage: TProgressStage;
  PercentDone: Byte;  RedrawNow: Boolean; const R: TRect; const Msg: string);
var
  T: Integer;
  {$IFDEF SG_CAD_DLL}
  Mesg: TMsg;
  {$ENDIF}
begin
  T := GetCurrentTime and not $FF;
  if (not FIsProcessMessages) or ((Stage=psRunning) and (T=FLast)) then
    Exit;
  FLast := T;
  {$IFNDEF SG_CAD_DLL}
  Application.ProcessMessages;
  {$ELSE}
  if Stage <> psStarting then
    if PeekMessage(Mesg, 0, 0, 0, PM_REMOVE) then
    begin
      TranslateMessage(Mesg);
      DispatchMessage(Mesg);
    end;
  {$ENDIF}
  inherited Progress(Sender,Stage,PercentDone,RedrawNow,R,Msg);
end;

function TsgDXFImage.GetLineScale: Double;
begin
  Result := fLineWeightFactor;
end;

function TsgDXFImage.GetLineWeight(const AWeight: Double): Integer;
begin
  if Abs(FmmToPixelX) > fAccuracy then
    Result := Ceil(GetLineScale * AWeight * 0.5/ FmmToPixelX)
  else
    Result := Ceil(GetLineScale * AWeight * 0.5);
end;

procedure TsgDXFImage.SaveToClipboardFormat(var Fmt: Word; var Data: THandle;
  var Pal: HPALETTE);
var
  S: TClipboardStream;
begin
  Fmt := 0; Data := 0; Pal := 0;
  if Converter.Source = nil then Exit;
  Fmt := CBFormat;
  S := TClipboardStream.Create(0);
  try
    SaveToStream(S);
    Data := S.Handle;
  finally
    S.Free;
  end;
  if Fmt = CF_DXF then
  begin
    Fmt := CF_TEXT;
    SetClipboardData(CF_DXF, GlobalAlloc(GMEM_MOVEABLE, 4));
  end;
end;

procedure TsgDXFImage.SetExtentsParameters(const ARect: TFRect; const AIs3DExtents: Boolean);
const
  flRatio = 16;
var
  vWidth, vHeight: TsgFloat;
  vRect: TFRect;
begin
  if IsBadRect(ARect) then
  begin
    FPureExtents := UnitRect;
    FXMax := FPureExtents.Right;
    FYMax := FPureExtents.Top;
    FZMax := FPureExtents.Z2;
    FXMin := FPureExtents.Left;
    FYMin := FPureExtents.Bottom;
    FZMin := FPureExtents.Z1;
    ResetExtents;
    Changed(Self);
    Exit;
  end;
  if IsBadRect(FDrawingBox) then
    vRect := ARect
  else
    vRect := FDrawingBox;
  FCenter.X := 0.5 * (vRect.Right + vRect.Left);
  FCenter.Y := 0.5 * (vRect.Top + vRect.Bottom);
  FCenter.Z := 0.5 * (vRect.Z1 + vRect.Z2);
  if AIs3DExtents then
    TransRectCorners(vRect, GetRealImageMatrix);
  FXMin := 0;
  FYMin := 0;
  FPureExtents := vRect;
  if not FIsWithoutBorder then
  begin
    case FBorderType of
      btRatio:
        begin
          FXMin := (vRect.Right - vRect.Left) * FBorderSize;
          FYMin := (vRect.Top - vRect.Bottom) * FBorderSize;
        end;
      btGlobal:
        begin
          FXMin := Abs(FBorderSize);
          FYMin := Abs(FBorderSize);
        end;
    end;
    if FXMin < 0 then
      FXMin := 1;
    if FYMin < 0  then
      FYMin := 1;
  end;
  if IsBadRect(vRect) then// for unsized model or layouts
  begin
    FPureExtents := UnitRect;
    FXMax := FPureExtents.Right;
    FYMax := FPureExtents.Top;
    FZMax := FPureExtents.Z2;
    FXMin := FPureExtents.Left;
    FYMin := FPureExtents.Bottom;
    FZMin := FPureExtents.Z1;
  end
  else
  begin
    FXMax := vRect.Right + FXMin;
    FYMax := vRect.Top + FYMin;
    FZMax := vRect.Z2;
    FXMin := vRect.Left - FXMin;
    FYMin := vRect.Bottom - FYMin;
    FZMin := vRect.Z1;
  end;
  FXDisproportionateShift := 0;
  FYDisproportionateShift := 0;
  if FResizeDisproportionateDrawing then
  begin
    vWidth := Abs(FXMax - FXMin);
    vHeight := Abs(FYMax - FYMin);
    if (vWidth <> 0)and(vHeight / vWidth > flRatio) or (vWidth = 0) then
    begin
      FXDisproportionateShift := (vHeight - vWidth) / 2;
      FXMin := FXMin - FXDisproportionateShift;
      FXMax := FXMax + FXDisproportionateShift;
    end
    else
      if (vHeight <> 0)and(vWidth / vHeight > flRatio) or (vHeight = 0) then
    begin
      FYDisproportionateShift := (vWidth - vHeight) / 2;
      FYMax := FYMax + FYDisproportionateShift;
      FYMin := FYMin - FYDisproportionateShift;
    end;
  end;
  ResetExtents;
  Changed(Self);
end;

procedure TsgDXFImage.SetOnInsertMode(const AIns: TsgDXFInsert);
begin
  FOnInsert := AIns;
  FOnInsertMode := False;
end;

procedure TsgDXFImage.SetHeight(Value: Integer);
begin
end;

procedure TsgDXFImage.SetMatrix;
var
  FP: TFPoint;
begin
  FP := PtXMat(FCenter, FDraw.Matrix);
  FDraw.Matrix[3, 0] := -FP.X;
  FDraw.Matrix[3, 1] := -FP.Y;
  FDraw.Matrix[3, 2] := -FP.Z;
  FDraw.Matrix := MatXMat(FDraw.Matrix, StdMat(FltPoint3D(1, 1, 1), FP));
  FDraw.Matrix := MatXMat(FDraw.Matrix, StdMat(Scale, MakeFPoint(0, 0, 0)));
  FDraw.Matrix := MatXMat(FDraw.Matrix, StdMat(FltPoint3D(1, -1, 1), MakeFPoint(0, 0, 0)))
end;

procedure TsgDXFImage.SetMillimetres(Value: Boolean);
begin
  FMillimetres := Ord(Value);
end;

procedure TsgDXFImage.SetSelectionMatrixProc(const AMode: TsgSelectionMode);
begin
  FSelectionMatrixMode := AMode;
end;

procedure TsgDXFImage.SetWidth(Value: Integer);
begin
end;

function TsgDXFImage.GetSHXFontsProc: TsgSHXFontList;
begin
  Result := Converter.SHXFonts;
end;

function TsgDXFImage.GetSelectionMatrixProc: TsgSelectionMode;
begin
  Result := FSelectionMatrixMode;
end;

procedure TsgDXFImage.ApplyBrush;
begin
  if FCanvas.Brush.Color <> clWhite then
    case FDrawMode of
      dmBlack:
        FCanvas.Brush.Color := FDefaultColor;
      dmGray:
        FCanvas.Brush.Color := clGray;
    end;
end;

procedure TsgDXFImage.ApplyPen(Sender: TObject);
var
  W, I, vPos: Integer;
  Cl: TColor;
  DS: Char;
  vFlag: Boolean;
  vLineWeight: Double;

  function SGStringToColor(const S: string): TColor;
  begin
    if (not IdentToColor(S, Longint(Result))) then
      Result := TColor(StrToIntDef(S, 0));
  end;
begin
  vFlag := False;
  if Sender is TsgDXFPenLine then
    vFlag := TsgDXFPenLine(Sender).Pen.Style <> psSolid;
  vLineWeight := EntLineWeight(TsgDXFEntity(Sender), FDraw.Insert);
  if vFlag or (vLineWeight = 0.0) or (not IsShowLineWeight) then
    W := 0
  else
    W := Ceil(GetLineScale * vLineWeight / FmmToPixelX);
  if W <= 0 then
    W := FNullWidth;
  W := Round(FLineWeightScale * W);
  if (FColorToLineWeight.Count <> 0) {and FIsShowLineWeight} then
  begin
    for I := 0 to FColorToLineWeight.Count - 1 do
    begin
      vPos := AnsiPos('=', FColorToLineWeight[I]);
      if vPos = 0 then
        Continue;
      Cl := SGStringToColor(Trim(Copy(FColorToLineWeight[I], 0, vPos - 1)));
      DS := DecimalSeparator;
      DecimalSeparator := '.';
      try
        if (FCanvas.Pen.Color = Cl)
          or ((FCanvas.Pen.Color = clNone) and (Cl = clBlack))
          or ((Cl = clNone) and (FCanvas.Pen.Color = FDefaultColor))then
          W := Round(ConvToFloatDef(Trim(Copy(FColorToLineWeight[I],
	    vPos + 1, Length(FColorToLineWeight[I]))), 0.0) / FmmToPixelX);
      finally
        DecimalSeparator := DS;
      end;
    end;
    W := Round(FLineWeightScale * W);
  end;
  FCanvas.Pen.Width := W;
  if (not LineScaled) then
    FCanvas.Pen.Width := FNullWidth;
  if FCanvas.Pen.Color <> clWhite then
    case FDrawMode of
      dmBlack:
        FCanvas.Pen.Color := FDefaultColor;
      dmGray:
        FCanvas.Pen.Color := clGray;
    end;
end;

procedure TsgDXFImage.ApplyScale(AWidth,AHeight: Integer);
// for drawing in given sizes
var
  P: TFPoint;
  XMin, YMin, XMax, YMax: Double;
begin
  XMin := Extents.Left;
  XMax := Extents.Right;
  YMin := Extents.Bottom;
  YMax := Extents.Top;
  XMax := XMax - XMin;
  YMax := YMax - YMin;
  if AWidth = 0 then
    AWidth := 1;
  if AHeight = 0 then
    AHeight := 1;
  if XMax = 0 then
    XMax := AWidth;
  if YMax = 0 then
    YMax := AHeight;
  XMin := AWidth / XMax;
  YMin := AHeight / YMax;
  if not Stretch then
  begin
    if Abs(XMin) > Abs(YMin) then
      XMin := YMin;
    if Abs(YMin) > Abs(XMin) then
      YMin := XMin;
  end;
  FScale.X := XMin;
  FScale.Y := YMin;
  FScale.Z := XMin;
  if Abs(XMin) > Abs(YMin) then
    FScale.Z := YMin;
  if FCurrentLayout.IsModel then
    FDraw.Matrix := MatXMat(FConverter.ViewTwistMatrix, FCurrentLayout.RotMatrix)
  else
    FDraw.Matrix := FCurrentLayout.RotMatrix;
  SetMatrix;
  P := PtXMat(FCenter, FDraw.Matrix);
  FDX := AWidth shr 1 - P.X;
  FDY := AHeight shr 1 - P.Y;
end;

procedure TsgDXFImage.ApplyText;
begin
  case FDrawMode of
    dmBlack:
      begin
        FCanvas.Font.Color := FDefaultColor;
        FCanvas.Pen.Color := FDefaultColor;
      end;
    dmGray:
      begin
        FCanvas.Font.Color := clGray;
        FCanvas.Pen.Color := clGray;
      end;
  end;
end;

procedure TsgDXFImage.BeginRead(Sender: TObject);
begin
  DoProgress(psStarting);
end;

procedure TsgDXFImage.BoxPoint(const P: TFPoint);
var
  IP: TPoint;
begin
  IP := GetPoint(P);
  ExpandRect(FIRect, IP);
  if FIndex < 8 then
    FIPoints[FIndex] := IP;
  Inc(FIndex);
end;

procedure TsgDXFImage.DoProgress(Stage: TProgressStage);        // OnProgress event
const
  R: TRect = (Left: 0; Top: 0; Right: 0; Bottom: 0);
begin
  if not Assigned(OnProgress) then
    Exit;
  Progress(Self, Stage, Byte(MulDiv(FConverter.Pos, 100, FConverter.Count)),
     False, R, FMsg);
end;

procedure TsgDXFImage.DoRead(Sender: TObject);
begin
  DoProgress(psRunning);
end;

procedure TsgDXFImage.DrawArc(Sender: TObject);
var
  R: TRect;
  P1, P2: TPoint;
  A: TsgArc;
begin
//Self := Drawing;
  if FUseWinEllipse and TsgDXFCircle(Sender).Lines.IsSolid and (Converter.VPort.X = 0)
      and (Converter.VPort.Y = 0) and (Converter.VPort.Z > 0) and (not IsDrawingRotated) then
  begin
    A := EntArc(TsgDXFArc(Sender), FDraw);
    if not A.Valid then
    begin
      DrawPoly(Sender);
      Exit;
    end;
    ApplyPen(TsgDXFCircle(Sender));
    R.Left := Round(A.Rect.Left);
    R.Top := Round(A.Rect.Top);
    R.Right := Round(A.Rect.Right);
    R.Bottom := Round(A.Rect.Bottom);
    P1.X := Round(A.Point1.X);
    P1.Y := Round(A.Point1.Y);
    P2.X := Round(A.Point2.X);
    P2.Y := Round(A.Point2.Y);
    if IsDrawOnBitMap then
    begin
      AddSelectionMatrix(Sender);
      if (P1.X = P2.X) and (P1.Y = P2.Y) then
        SetPixelV(SelectionMatrix.Canvas.Handle, P1.X, P1.Y, SelectionMatrix.Canvas.Pen.Color)
      else
        SelectionMatrix.Canvas.Arc(R.Left, R.Top, R.Right, R.Bottom, P1.X, P1.Y, P2.X, P2.Y);
    end;
    if IsDrawOnCanvas then
    begin
      if (P1.X = P2.X) and (P1.Y = P2.Y) then
        SetPixelV(FCanvas.Handle, P1.X, P1.Y, FCanvas.Pen.Color)
      else
        FCanvas.Arc(R.Left, R.Top, R.Right, R.Bottom, P1.X, P1.Y, P2.X, P2.Y);
    end;
  end
  else
    DrawPoly(Sender);
end;

procedure TsgDXFImage.DrawCircle(Sender: TObject);
var
  C: TsgDXFCircle absolute Sender;
  R: TRect;

  function CBounds: TRect;
  var
    OffsetPt: TPoint;
  begin
    Result.TopLeft := GetPoint(C.Point);
    Result.BottomRight := Result.TopLeft;
    DoScale2D(FDraw);
    OffsetPt.X := Abs(Round(C.Radius * FDraw.XScale {* Scale.X}));
    OffsetPt.Y := Abs(Round(C.Radius * FDraw.YScale {* Scale.Y}));
    InflateRect(Result, OffsetPt.X, OffsetPt.Y);
  end;
begin
//Self := Drawing;
  if FUseWinEllipse and (not Converter.Is3D)
    and C.Lines.IsSolid and (Converter.VPort.X = 0)
      and (Converter.VPort.Y = 0) and (Converter.VPort.Z > 0) and (not IsDrawingRotated) then
  begin
    ApplyPen(C);
    R := CBounds;
    if IsDrawOnBitMap then
    begin
      AddSelectionMatrix(Sender);
      SelectionMatrix.Canvas.Brush.Style := bsClear;
      SelectionMatrix.Canvas.Ellipse(R.Left, R.Top, R.Right, R.Bottom);
    end;
    if IsDrawOnCanvas then
    begin
      FCanvas.Brush.Style := bsClear;
      FCanvas.Ellipse(R.Left, R.Top, R.Right, R.Bottom);
    end;
  end
  else
    DrawPoly(Sender);
end;

procedure TsgDXFImage.DrawFace(Sender: TObject);
  procedure Edge(Lines: TsgLines; const F1, F2: TFPoint);
  var
    P: TPoint;
    I: Integer;
    AList: TList;
  begin
    if Lines.IsSolid then
    begin
      FIntPoints.Count := 0;
      for I := 0 to 1 do
      begin
      if I = 0 then
        P := GetPoint(F1)
      else
        P := GetPoint(F2);
        FIntPoints.Add(Pointer(P.X));
        FIntPoints.Add(Pointer(P.Y));
      end;
      if IsDrawOnBitMap then
      begin
        AddSelectionMatrix(Sender);
        DrawPolyLine(SelectionMatrix.Canvas.Handle, FIntPoints);
      end;
      if IsDrawOnCanvas then
        DrawPolyLine(FCanvas.Handle, FIntPoints)
    end
    else
    begin
      AList := TList.Create;
      try
        Lines.Line(F1, F2, AList);
        DrawPointsListByPolyPolyline(Sender, AList);
      finally
        for I := 0 to AList.Count - 1 do
          Dispose(AList[I]);
        AList.Free;
      end;
    end;
  end;
var
  F: TsgDXF3dFace absolute Sender;
begin
//Self := Drawing;
  ApplyPen(Sender);
  if F.Flags and 1 = 0 then
    Edge(F.Lines, F.Point, F.Point1);
  if F.Flags and 2 = 0 then
    Edge(F.Lines, F.Point1, F.Point2);
  if F.Flags and 4 = 0 then
    Edge(F.Lines, F.Point2, F.Point3);
  if F.Flags and 8 = 0 then
    Edge(F.Lines,F.Point3, F.Point);
end;

procedure TsgDXFImage.DrawHatch(Sender: TObject);
var
  P1: TPoint;
  vPolygon: TsgCADPolyPolygon;
  vHatch: TsgCADHatch;
  vRgn,vMainRGN, vClipRgn: HRGN;
  I, SaveIndex: Integer;
  vList: TList;
  vFP: TFPoint;
  vRect: TRect;
  Vert: array[0..1] of TTriVertex;
  
  procedure SetVert(var V: TTriVertex; const P: TPoint; C: TColor);
  begin
    V.X := P.X; V.Y := P.Y;
    V.Red := C and $FF shl 8;
    V.Green := C and $FF00;
    V.Blue := C and $FF0000 shr 8;
    V.Alpha := 0;
  end;

{$IFDEF SG_USEGDIPLUS}
  function GetGDIPlusColor(AColor: TColor): Cardinal;
  var
    vColors: array [0..3] of Byte absolute AColor;
  begin
    Result := MakeColor(255 - vColors[3], vColors[0], vColors[1], vColors[2]);
  end;


  procedure DrawGDIPlusGradientLinear(DC: HDC; AIsVerticalGradient: Boolean; AP1, AP2: PPoint; AC1, AC2: TColor);
  var
    graphics: TsgGDIPlusGraphics;
    GradL: TsgGDIPlusLinearGradientBrush;
    GPRect: TsgGRect;
    GP1, GP2: TsgGPoint;
    GColor1, GColor2: TsgColor;
  begin
    GP1.X := AP1^.X;
    GP1.Y := AP1^.Y;
    if AIsVerticalGradient then
    begin
      GP2.X := GP1.X;
      GP2.Y := AP2^.Y;
    end
    else
    begin
      GP2.X := AP2^.X;
      GP2.Y := GP1.Y;
    end;
    GPRect := MakeRect(AP1^.X, AP1^.Y, AP2^.X - AP1^.X, AP2^.Y - AP1^.Y);
    GColor1 := GetGDIPlusColor(AC1);
    GColor2 := GetGDIPlusColor(AC2);
    graphics := TsgGDIPlusGraphics.Create(DC);
    GradL := TsgGDIPlusLinearGradientBrush.Create(GP1, GP2, GColor1, GColor2);
    graphics.FillRectangle(GradL, GPRect);
    GradL.Free;
    graphics.Free;
  end;

  procedure DrawGDIPlusGradientRadial(DC: HDC; AP1, AP2: PPoint; AC1, AC2: TColor);
  var
    graphics: TsgGDIPlusGraphics;
    GradP: TsgGDIPlusPathGradientBrush;
    GPRect: TsgGRect;
    GColor1, GColor2: TsgColor;
    vColors1: array [0..3] of Byte absolute AC1;
    vColors2: array [0..3] of Byte absolute AC2;
    GPath: TsgGDIPlusGraphicsPath;
    vCount: Integer;
  begin
    GPRect := MakeRect(AP1^.X, AP1^.Y, AP2^.X - AP1^.X, AP2^.Y - AP1^.Y);
    GColor1 := GetGDIPlusColor(AC1);
    GColor2 := GetGDIPlusColor(AC2);
    vCount := 1;
    graphics := TsgGDIPlusGraphics.Create(DC);
    GPath :=  TsgGDIPlusGraphicsPath.Create;
    GPath.StartFigure;
    GPath.AddEllipse(GPRect);
    GPath.SetFillMode(FillModeWinding);
    GradP := TsgGDIPlusPathGradientBrush.Create(GPath);
    GradP.SetCenterColor(GColor1);
    GradP.SetCenterPoint(MakePoint((AP2^.X + AP1^.X) shr 1, (AP2^.Y + AP1^.Y) shr 1));
    GradP.SetSurroundColors(@GColor2, vCount);
    graphics.FillPath(GradP, GPath);
    GradP.Free;
    GPath.Free;
    graphics.Free;
  end;

  procedure DrawGDIPlusHatch(DC: HDC; AColor: TColor);
  var
    graphics: TsgGDIPlusGraphics;
    Solid: TsgGDIPlusSolidBrush;
    GPRect: TsgGRect;
    vRGNTmp: HRGN;
    vColor: TColor;
  begin
    GetRgnBox(vMainRGN, vRect);
    P1 := Point(0,0);
    LPtoDP(FCanvas.Handle, P1, 1);
    OffsetRgn(vMainRGN, P1.X, P1.Y);
    P1 := Point(0,1);
    vRGNTmp := CreateRectRgn(0, 0, 0, 0);
    if GetClipRgn(FCanvas.Handle, vRGNTmp) > 0 then
      CombineRgn(vMainRGN, vMainRGN, vRGNTmp, RGN_AND);
    DeleteObject(vRGNTmp);
    SelectClipRgn(FCanvas.Handle, vMainRGN);
    GPRect := MakeRect(vRect.TopLeft.X, vRect.TopLeft.Y, vRect.BottomRight.X - vRect.TopLeft.X, vRect.BottomRight.Y - vRect.TopLeft.Y);
    graphics := TsgGDIPlusGraphics.Create(DC);
    case vPolygon.Color of
      clByBlock, clByLayer, clNone: vColor := AColor;
    else
      vColor := vPolygon.Color;
    end;
    Solid := TsgGDIPlusSolidBrush.Create(GetGDIPlusColor(vColor));
    graphics.FillRectangle(Solid, GPRect);
    Solid.Free;
    graphics.Free;
  end;

  function GetRectMaxSize(const ARect: TsgGRect): TsgGRect;
  begin
    if ARect.Width < ARect.Height then
      Result.Width := ARect.Height
    else
      Result.Width := ARect.Width;
    Result.Height := ARect.Width;
    Result.X := ARect.X - (Result.Width - ARect.Width) div 2;
    Result.Y := ARect.Y - (Result.Height - ARect.Height) div 2;
  end;

  function GetRectRotated(const ARect: TRect; const Angle: Double): TRect;
  var
    vC: TPoint;
  begin
    Result := ARect;
    vC.X := (ARect.Left + ARect.Right) div 2;
    vC.Y := (ARect.Top + ARect.Bottom) div 2;
    ExpandRect(Result, GetPointOfRotateByCenter(Point(ARect.Left, ARect.Top), vC, Angle));
    ExpandRect(Result, GetPointOfRotateByCenter(Point(ARect.Right, ARect.Top), vC, Angle));
    ExpandRect(Result, GetPointOfRotateByCenter(Point(ARect.Right, ARect.Bottom), vC, Angle));
    ExpandRect(Result, GetPointOfRotateByCenter(Point(ARect.Left, ARect.Bottom), vC, Angle));
  end;

  procedure DrawGDIPlusCADGradient(const ACADGradinet: TsgCADGradientPolygonAccess);
  const
    cnstCounts: Integer = 3;
    cnstBlendFactorsByCylinder: array [0..2] of Single = (0, 1, 0);
    cnstBlendPositionsByCylinder: array [0..2] of Single = (0, 0.5, 1);
    cnstBlendFactorsByCylinderNotCenter: array [0..2] of Single = (0, 1, 0);
    cnstBlendPositionsByCylinderNotCenter: array [0..2] of Single = (0, 0.2, 1);
    cnstBlendFactorsByLiner: array [0..2] of Single = (0, 0.5, 1);
    cnstBlendPositionsByLinear: array [0..2] of Single = (0, 0.2, 1);
  var
    vColors: array [0..1] of TsgColor;
    graphics: TsgGDIPlusGraphics;
    GRect, GR: TsgGRect;
    GCenter: TsgGPoint;
    GMatrix: TsgGDIPlusMatrix;
    GGradL: TsgGDIPlusLinearGradientBrush;
    vRectRot: TRect;

    procedure DrawSolid(const AColor: TsgColor);
    var
      GSolid: TsgGDIPlusSolidBrush;
    begin
      GSolid := TsgGDIPlusSolidBrush.Create(AColor);
      try
        graphics.FillRectangle(GSolid, GRect);
      finally
        GSolid.Free;
      end;
    end;

    procedure DrawSpheric(const ARect: TsgGRect; const ACenter: TsgGPoint);
    var
      GPath: TsgGDIPlusGraphicsPath;
      GGrad: TsgGDIPlusPathGradientBrush;
      vCount: Integer;
    begin
      GPath := TsgGDIPlusGraphicsPath.Create;
      try
        GPath.StartFigure;
        GPath.AddEllipse(ARect);
        GGrad := TsgGDIPlusPathGradientBrush.Create(GPath);
        try
          vCount := 1;
          //GGrad.MultiplyTransform(GMatrix);
          GGrad.SetCenterColor(vColors[1]);
          GGrad.SetCenterPoint(ACenter);
          GGrad.SetSurroundColors(@vColors[0], vCount);
          graphics.FillPath(GGrad, GPath);
        finally
          GGrad.Free;
        end;
      finally
        GPath.Free;
      end;
    end;

  begin
    vColors[0] := GetGDIPlusColor(vPolygon.Color);
    vColors[1] := GetGDIPlusColor(ACADGradinet.GradientColor);
    if ACADGradinet.FType in [gtInvCurved, gtInvCylinder, gtInvHemiSpherical, gtInvSpherical] then
      SwapInts(vColors[0], vColors[1]);
    GRect := MakeRectI(vRect);
    graphics := TsgGDIPlusGraphics.Create(FCanvas.Handle);
    try
      case ACADGradinet.FType of
        gtLinear:
          begin
            GMatrix := TsgGDIPlusMatrix.Create(1, 0, 0, 1, 0, 0);
            try
              if Abs(ACADGradinet.GradientAngle) > fAccuracy then
              begin
                vRectRot := GetRectRotated(vRect, 360 - ACADGradinet.GradientAngle);
                GRect := MakeRectI(vRectRot);
                GMatrix.RotateAt(360 - ACADGradinet.GradientAngle, PointIToPointF(GetCenter(TsgGRect(GRect))));
              end;
              GGradL := TsgGDIPlusLinearGradientBrush.Create(GRect, vColors[0], vColors[1],LinearGradientModeHorizontal);
              try
                GGradL.MultiplyTransform(GMatrix);
                if not ACADGradinet.GradientUseCenter then
                  GGradL.SetBlend(@cnstBlendFactorsByLiner, @cnstBlendPositionsByLinear, cnstCounts);
                graphics.FillRectangle(GGradL, GRect);
              finally
                GGradL.Free;
              end;
            finally
              GMatrix.Free;
            end;
          end;
        gtCylinder, gtInvCylinder:
          begin
            GMatrix := TsgGDIPlusMatrix.Create(1, 0, 0, 1, 0, 0);
            try
              if Abs(ACADGradinet.GradientAngle) > fAccuracy then
              begin
                vRectRot := GetRectRotated(vRect, 360 - ACADGradinet.GradientAngle);
                GRect := MakeRectI(vRectRot);
                GMatrix.RotateAt(360 - ACADGradinet.GradientAngle, PointIToPointF(GetCenter(GRect)));
              end;
              GGradL := TsgGDIPlusLinearGradientBrush.Create(GRect, vColors[0], vColors[1],LinearGradientModeHorizontal);
              try
                GGradL.MultiplyTransform(GMatrix);
                if ACADGradinet.GradientUseCenter then
                  GGradL.SetBlend(@cnstBlendFactorsByCylinder, @cnstBlendPositionsByCylinder, cnstCounts)
                else
                  GGradL.SetBlend(@cnstBlendFactorsByCylinderNotCenter, @cnstBlendPositionsByCylinderNotCenter, cnstCounts);
                graphics.FillRectangle(GGradL, GRect);
              finally
                GGradL.Free;
              end;
            finally
              GMatrix.Free;
            end;
          end;
        gtSpherical, gtInvSpherical:
          begin
            DrawSolid(vColors[0]);
            vRect := GetRectRotated(vRect, 360 - ACADGradinet.GradientAngle);
            GRect := MakeRectI(vRect);
            GR := GetRectMaxSize(GRect);
            if ACADGradinet.GradientUseCenter then
              GCenter := GetCenter(GR)
            else
            begin
              GCenter.X := GR.X + Round(0.2 * GR.Width);
              GCenter.Y := GR.Y + Round(0.2 * GR.Height);
              GR.X := GCenter.X - GR.Width div 2;
              GR.Y := GCenter.Y - GR.Height div 2;
            end;
            DrawSpheric(GR, GCenter);
          end;
        gtHemiSpherical, gtInvHemiSpherical:
          begin
            DrawSolid(vColors[0]);
            if ACADGradinet.GradientUseCenter then
            begin
              GCenter.X := GRect.X + GRect.Width div 2;
              GCenter.Y := GRect.Y + GRect.Height;
            end
            else
            begin
              GCenter.X := GRect.X;
              GCenter.Y := GRect.Y + GRect.Height;
            end;
            if GRect.Width > GRect.Height then
              GR.Width := GRect.Width shl 1
            else
              GR.Width := GRect.Height shl 1;
            GR.Height := GR.Width;
            GR.X := GCenter.X - GR.Width div 2;
            GR.Y := GCenter.Y - GR.Height div 2;
            DrawSpheric(GR, GCenter);
          end;
        gtCurved, gtInvCurved:
          begin
            GGradL := TsgGDIPlusLinearGradientBrush.Create(GRect, vColors[0], vColors[1], LinearGradientModeVertical);
            try
              graphics.FillRectangle(GGradL, GRect);
            finally
              GGradL.Free;
            end;
          end;
      end;
    finally
      graphics.Free;
    end;
  end;
{$ENDIF}

  procedure DrawGradient;
  var
    Per: TsgFloat;
    L: Integer;
    vP1,vP2: TPoint;
    vGradient: TsgDXFGradient;
    vColor: TColor;
    vRGNTmp: HRGN;
    vRectEnt: TRect;
    vR: TFRect;

    function AverageColors(AColor1, AColor2: TColor): TColor;
    var
      vColors1: array [0..3] of Byte absolute AColor1;
      vColors2: array [0..3] of Byte absolute AColor2;
      vColorsR: array [0..3] of Byte absolute Result;
    begin
      vColorsR[0] := (vColors1[0] + vColors2[0]) shr 1;
      vColorsR[1] := (vColors1[1] + vColors2[1]) shr 1;
      vColorsR[2] := (vColors1[2] + vColors2[2]) shr 1;
      vColorsR[3] := 0;
    end;

  begin
    //if not(vPolygon is TsgCADGradientPolygon) then Exit;
    GetRgnBox(vMainRGN, vRect);
    P1 := Point(0,0);
    LPtoDP(FCanvas.Handle, P1, 1);
    OffsetRgn(vMainRGN, P1.X, P1.Y);
    P1 := Point(0,1);
    vRGNTmp := CreateRectRgn(0, 0, 0, 0);
    if GetClipRgn(FCanvas.Handle, vRGNTmp) > 0 then
      CombineRgn(vMainRGN, vMainRGN, vRGNTmp, RGN_AND);
    DeleteObject(vRGNTmp);
    SelectClipRgn(FCanvas.Handle, vMainRGN);
    vP1 := vRect.TopLeft;
    vP2 := vRect.BottomRight;
    if Sender.ClassType <> TsgDXFGradient then
    begin
{$IFDEF SG_USEGDIPLUS}
      if FLibraryGDIPlusExists then
        DrawGDIPlusCADGradient(TsgCADGradientPolygonAccess(vPolygon))
      else
{$ENDIF}
      begin
        SetVert(Vert[0], vP1, vPolygon.Color);
        SetVert(Vert[1], vP2, TsgCADGradientPolygon(vPolygon).GradientColor);
        GradientFill(FCanvas.Handle, @Vert, 2, @P1, 1, 1);
      end;
    end
    else
    begin
      vGradient := TsgDXFGradient(Sender);
      vR := vGradient.Box;
      TransRectCorners(vR, FDraw.Matrix);
      vRectEnt.TopLeft := Point(Round(vR.TopLeft.X), Round(vR.TopLeft.Y));
      vRectEnt.BottomRight := Point(Round(vR.BottomRight.X), Round(vR.BottomRight.Y));
      SwapInts(vRectEnt.TopLeft.Y, vRectEnt.BottomRight.Y);
      if vGradient.Radius <= 0 then
      begin
        if vGradient.IsVerticalGradient then
          Per := (vRectEnt.Bottom - vRectEnt.Top) / 100
        else
          Per := (vRectEnt.Right - vRectEnt.Left) / 100;
        for L := 0 to vGradient.GradientColors.Count - 2 do
        begin
          if vGradient.IsVerticalGradient then
          begin
            vP1.Y := vRectEnt.TopLeft.Y + Round(Single(vGradient.PercentFill[L]) * Per);
            vP2.Y := vRectEnt.TopLeft.Y + Round(Single(vGradient.PercentFill[L + 1]) * Per);
          end
          else
          begin
            vP1.X := vRectEnt.TopLeft.X + Round(Single(vGradient.PercentFill[L]) * Per);
            vP2.X := vRectEnt.TopLeft.X + Round(Single(vGradient.PercentFill[L + 1]) * Per);
          end;
{$IFDEF SG_USEGDIPLUS}
          if FLibraryGDIPlusExists then
            DrawGDIPlusGradientLinear(FCanvas.Handle, vGradient.IsVerticalGradient, @vP1, @vP2, TColor(vGradient.GradientColors[L]), TColor(vGradient.GradientColors[L + 1]))
          else
{$ENDIF}
          begin
            SetVert(Vert[0], vP1, TColor(vGradient.GradientColors[L]));
            SetVert(Vert[1], vP2, TColor(vGradient.GradientColors[L + 1]));
            GradientFill(FCanvas.Handle, @Vert, 2, @P1, 1, Integer(vGradient.IsVerticalGradient));
          end;
        end;
      end
      else
      begin
{$IFDEF SG_USEGDIPLUS}
        if FLibraryGDIPlusExists then
          DrawGDIPlusGradientRadial(FCanvas.Handle, @vRectEnt.TopLeft, @vRectEnt.BottomRight, TColor(vGradient.GradientColors.First), TColor(vGradient.GradientColors.Last))
        else
{$ENDIF}
        begin
          vColor := AverageColors(TColor(vGradient.GradientColors[0]), TColor(vGradient.GradientColors[1]));
          SetVert(Vert[0], vP1, vColor);
          SetVert(Vert[1], vP2, vColor);
          GradientFill(FCanvas.Handle, @Vert, 2, @P1, 1, 1);
        end;
      end;
    end;
  end;

  procedure Load2DPointToPoly;
  var
    J: Integer;
  begin
    for J := 0 to vList.Count - 1 do      // prepares TPoint array for GDI
    begin
      vFP.X := PF2DPoint(vList[J]).X;
      vFP.Y := PF2DPoint(vList[J]).Y;
      P1 := GetPoint(vFP);
      FPoly.Add(Pointer(P1.X));
      FPoly.Add(Pointer(P1.Y));
    end;
  end;

begin
//Self := Drawing;
  if Sender is TsgCADHatch then
    vHatch := TsgCADHatch(Sender)
  else
    vHatch := nil;
  vPolygon := TsgCADPolyPolygon(Sender);

  vClipRgn := 0;
  vMainRGN := CreateRectRgn(0, 0, 0, 0);// FCanvas.ClipRect.Right, FCanvas.ClipRect.Bottom);
  vFP.Z := 0;
  ApplyPen(Sender);
  SaveIndex := SaveDC(FCanvas.Handle);
  try
    if (sgClientRect.Left <> MaxInt)and(sgClientRect.Top <> MaxInt) then
      vClipRgn := CreateRectRgn(sgClientRect.Left, sgClientRect.Top, sgClientRect.Right, sgClientRect.Bottom)
    else
      if (FClippingRect <> nil) and (sgClientRect.Right <> -MaxInt) then
        vClipRgn := CreateRectRgn(0, 0, sgClientRect.Right, sgClientRect.Bottom);
    for I := 0 to vPolygon.Boundaries.Count - 1 do
    begin
      FPoly.Clear;
      vList := vPolygon.Boundaries[I];
      Load2DPointToPoly;
      vRGN := CreatePolygonRgn(FPoly.List^, FPoly.Count shr 1, WINDING);
      if vClipRgn <> 0 then
        CombineRgn(vRGN, vClipRgn, vRGN,  RGN_AND);
      CombineRgn(vMainRGN, vRGN, vMainRGN,  RGN_XOR);
      DeleteObject(vRGN);
    end;
    //if sgClientRect.Left <> MaxInt then

    if (sgClientRect.Left <> MaxInt)and(sgClientRect.Top <> MaxInt) then
    begin
      DeleteObject(vClipRgn);
      GetRgnBox(vMainRGN, vRect);
      if vRect.Right = vRect.Left then
        Exit;
    end;
    if FCanvas is TMetafileCanvas then
    begin
      vRGN := CreateRectRgn(0, 0, 0, 0);
      GetClipRgn(FCanvas.Handle, vRGN);
      GetRgnBox(vRGN, vRect);
      if vRect.Right <> vRect.Left then
      	CombineRgn(vMainRGN, vMainRGN, vRGN, RGN_AND);
      DeleteObject(vRGN);
    end;
    if vHatch = nil then
    begin
      if (vPolygon is TsgCADGradientPolygon) and(TsgCADGradientPolygonAccess(vPolygon).FType <> gtNone) then
      begin
        if IsDrawOnCanvas then
           DrawGradient;
        if IsDrawOnBitMap then
        begin
          AddSelectionMatrix(Sender);
          SelectionMatrix.Canvas.Brush.Style := bsSolid;
          if vPolygon.Boundaries.Count = 1 then
            Polygon(SelectionMatrix.Canvas.Handle, FPoly.List^, FPoly.Count shr 1)
          else
            FillRgn(SelectionMatrix.Canvas.Handle, vMainRGN, SelectionMatrix.Canvas.Brush.Handle);
          SelectionMatrix.Canvas.Brush.Style := bsClear;
        end;
      end
      else
      begin
        if not FLibraryGDIPlusExists then
        begin
          FCanvas.Brush.Style := bsSolid;
          FCanvas.Brush.Color := FCanvas.Pen.Color;
          ApplyBrush;
          if vPolygon.Boundaries.Count = 1 then
          begin
            if IsDrawOnBitMap then
            begin
              AddSelectionMatrix(Sender);
              SelectionMatrix.Canvas.Brush.Style := bsSolid;
              Polygon(SelectionMatrix.Canvas.Handle, FPoly.List^, FPoly.Count shr 1);
              SelectionMatrix.Canvas.Brush.Style := bsClear;
            end;
            if IsDrawOnCanvas then
              Polygon(FCanvas.Handle, FPoly.List^, FPoly.Count shr 1);
          end
          else
          begin
            if IsDrawOnBitMap then
            begin
              AddSelectionMatrix(Sender);
              SelectionMatrix.Canvas.Brush.Style := bsSolid;
              FillRgn(SelectionMatrix.Canvas.Handle, vMainRGN, SelectionMatrix.Canvas.Brush.Handle);
              SelectionMatrix.Canvas.Brush.Style := bsClear;
            end;
            if IsDrawOnCanvas then
              FillRgn(FCanvas.Handle, vMainRGN, FCanvas.Brush.Handle);
          end;
        end
{$IFDEF SG_USEGDIPLUS}
        else
        begin
          if IsDrawOnBitMap then
          begin
            AddSelectionMatrix(Sender);
            SelectionMatrix.Canvas.Brush.Style := bsSolid;
            if vPolygon.Boundaries.Count = 1 then
              Polygon(SelectionMatrix.Canvas.Handle, FPoly.List^, FPoly.Count shr 1)
            else
              FillRgn(SelectionMatrix.Canvas.Handle, vMainRGN, SelectionMatrix.Canvas.Brush.Handle);
            SelectionMatrix.Canvas.Brush.Style := bsClear;
          end;
          if IsDrawOnCanvas then
            DrawGDIPlusHatch(FCanvas.Handle, FCanvas.Pen.Color);
        end;
{$ENDIF}
      end;
      Exit;
    end;

   DrawPointsListByPolyPolyline(Sender, vHatch.ParsedLines);
  finally
    RestoreDC(FCanvas.Handle, SaveIndex);
    DeleteObject(vMainRGN);
    FCanvas.Brush.Style := bsClear;
  end;
end;

function TsgDXFImage.DrawInsert(Sender: TObject): Integer;
var
  Ins: TsgDXFInsert absolute Sender;
begin
  Result := Integer(Ins.Block <> nil);
  if Result = 1 then
  begin
    if FOnInsert = Sender then
      FOnInsertMode := True;
    AddSelectionMatrix(Sender);
  end;
  if Ins is TsgCADClipInsert then
    SetClip(TsgCADClipInsert(Ins));
end;

function TsgDXFImage.DrawDimension(Sender: TObject): Integer;
var
  vDim: TsgDXFDimension absolute Sender;
begin
  Result := Integer(FDimensionsVisible and (vDim.Block <> nil));
  if Result = 1 then
    AddSelectionMatrix(Sender);
end;

procedure TsgDXFImage.DrawViewPort(Sender: TObject);
var
  vIsDrawOnBitMap: Boolean;
  vIsDrawOnCanvas: Boolean;
  ClipBoundary: TsgDXFEntity;
  ViewPort: TsgDXFViewPort;
  TopLeft, BottomRight, TopRight, BottomLeft, OffsetPt: TPoint;
  vFRect: TFRect;
  I: Integer;
  vRgn: HRGN;

  procedure AddPolyPoint(APoint: TPoint);
  begin
    FPoly.Add(Pointer(APoint.X));
    FPoly.Add(Pointer(APoint.Y));
  end;

  procedure CreateHRGNByRegion(vRegion: TsgDXFRegion);
  var
    J, vHandle: Integer;
    vEntity: TsgDXFEntity;
    vLine: TsgDXFLine absolute vEntity;
    vCurve: TsgDXFPolyline absolute vEntity;

    procedure AddCurve;

      function GetCoEdgeReversed(AEntity: TsgDXFPolyline): Boolean;
      begin
        Result := (AEntity.Flags and 8) <> 0;
      end;

    var
      K: Integer;
    begin
      if GetCoEdgeReversed(vCurve) then
      begin
        for K := vCurve.PolyPoints.Count - 1 downto 0 do
          AddPolyPoint(GetPoint(vCurve.Points[K]));
      end
      else
      begin
        for K := 0 to vCurve.PolyPoints.Count - 1 do
          AddPolyPoint(GetPoint(vCurve.Points[K]));
      end;
    end;

  begin
    J := 0;
    FViewPortRegion := CreateRectRgn(0, 0, 0, 0);
    repeat
      FPoly.Clear;
      vHandle := vRegion.Entities[J].Handle;
      while (J < vRegion.Count) and (vRegion.Entities[J].Handle = vHandle) do
      begin
        vEntity := vRegion.Entities[J];
        if vEntity is TsgDXFLine then
        begin
          AddPolyPoint(GetPoint(vLine.Point));
          AddPolyPoint(GetPoint(vLine.Point1));
        end
        else
          AddCurve;
        Inc(J);
      end;
      vRGN := CreatePolygonRgn(FPoly.List^, FPoly.Count shr 1, ALTERNATE);
      CombineRgn(FViewPortRegion, FViewPortRegion, vRGN, RGN_XOR);
      DeleteObject(vRGN);
      if ViewPort.VisibleBoundary then
      begin
        FCanvas.Brush.Style := bsClear;
        if IsDrawOnBitMap then
          Windows.Polyline(SelectionMatrix.Canvas.Handle, FPoly.List^, FPoly.Count shr 1);
        if IsDrawOnCanvas then
          Windows.Polyline(FCanvas.Handle, FPoly.List^, FPoly.Count shr 1);
      end;
    until J >= vRegion.Count;
  end;

begin
  vIsDrawOnBitMap := IsDrawOnBitMap;
  vIsDrawOnCanvas := IsDrawOnCanvas;
//Self := Drawing;
  New(FViewPortCanvasParams);
  FViewPortCanvasParams^.HDC := SaveDC(FCanvas.Handle);
  FViewPortCanvasParams^.CanvasParams.Brush := TBrush.Create;
  FViewPortCanvasParams^.CanvasParams.Font := TFont.Create;
  FViewPortCanvasParams^.CanvasParams.Pen := TPen.Create;
  FViewPortCanvasParams^.CanvasParams.Brush.Assign(FCanvas.Brush);
  FViewPortCanvasParams^.CanvasParams.Font.Assign(FCanvas.Font);
  FViewPortCanvasParams^.CanvasParams.Pen.Assign(FCanvas.Pen);
  ViewPort := TsgDXFViewPort(Sender);
  vFRect := ViewPort.Rect;
  TopLeft := GetPoint(vFRect.TopLeft);
  BottomRight := GetPoint(vFRect.BottomRight);
  TopRight := GetPoint(MakeFPoint(vFRect.Right, vFRect.Top, 0));
  BottomLeft := GetPoint(MakeFPoint(vFRect.Left, vFRect.Bottom, 0));
  ClipBoundary := ViewPort.GetBoundary(FConverter);
  FPoly.Count := 0;
  if vIsDrawOnBitMap then
    AddSelectionMatrix(Sender);
  if (ClipBoundary = nil) or not (ClipBoundary is TsgDXFPolyLine)
    or (TsgDXFPolyLine(ClipBoundary).PolyPoints.Count <= 2) then
  begin
    if (ClipBoundary is TsgDXFRegion) and (ClipBoundary.Count > 0) then
      CreateHRGNByRegion(TsgDXFRegion(ClipBoundary))
    else
    begin
      AddPolyPoint(TopLeft);
      AddPolyPoint(TopRight);
      AddPolyPoint(BottomRight);
      AddPolyPoint(BottomLeft);
      AddPolyPoint(TopLeft);
      FViewPortRegion := CreatePolygonRgn(FPoly.List^, FPoly.Count shr 1, ALTERNATE);
      if ViewPort.VisibleBoundary then
      begin
        if vIsDrawOnBitMap then
        begin
          SelectionMatrix.Canvas.Brush.Style := bsClear;
          Windows.Polyline(SelectionMatrix.Canvas.Handle, FPoly.List^, FPoly.Count shr 1);
        end;
        if vIsDrawOnCanvas then
        begin
          FCanvas.Brush.Style := bsClear;
          Windows.Polyline(FCanvas.Handle, FPoly.List^, FPoly.Count shr 1);
        end;
      end;
    end;
  end
  else
  begin //  only for classes for which TsgDXFPolyLine is parent
    for I := 0 to TsgDXFPolyLine(ClipBoundary).PolyPoints.Count - 1 do
      AddPolyPoint(GetPoint(PFPoint(TsgDXFPolyLine(ClipBoundary).PolyPoints[I])^));
    FViewPortRegion := CreatePolygonRgn(FPoly.List^, FPoly.Count shr 1, ALTERNATE);
  end;
  OffsetPt := Point(0, 0);
  LPtoDP(FCanvas.Handle, OffsetPt, 1);
  OffsetRgn(FViewPortRegion, OffsetPt.X, OffsetPt.Y);
//  if not IsBadRect(FDrawingBox) or (FClippingRect <> nil) then
//  begin
    vRgn := CreateRectRgn(0, 0, 0, 0);
    if GetClipRgn(FCanvas.Handle, vRgn) > 0 then
      CombineRgn(FViewPortRegion, FViewPortRegion, vRgn, RGN_AND);
    DeleteObject(vRgn);
//  end;
//  if vIsDrawOnBitMap then
//    SelectClipRgn(SelectionMatrix.Canvas.Handle, FViewPortRegion);
  if vIsDrawOnCanvas then
    SelectClipRgn(FCanvas.Handle, FViewPortRegion);
end;

procedure TsgDXFImage.DrawLeader(Sender: TObject);
begin
  if TsgDXFLeader(Sender).IsSpline = False then
    DrawPoly(Sender)
  else
    DrawSpline(Sender);
end;


procedure TsgDXFImage.DrawLine(Sender: TObject);
var
  vLine: TsgDXFLine absolute Sender;
  I, Cnt: Integer;
  vIsDrawOnBitMap, vIsDrawOnCanvas: Boolean;

  procedure DrawLineAndZTick(const APoint1, APoint2: PFPoint);
  var
    vPts: array [0..4] of TPoint;
  begin
    vPts[0] := GetPoint(APoint1^);
    vPts[1] := GetPoint(APoint2^);
    vPts[2] := GetPoint(MakeFPoint(APoint2^.X, APoint2^.Y, APoint2^.Z + vLine.ZThick));
    vPts[3] := GetPoint(MakeFPoint(APoint1^.X, APoint1^.Y, APoint1^.Z + vLine.ZThick));
    if IsEqualPoints(vPts[0], vPts[1]) and IsEqualPoints(vPts[1], vPts[2]) then
    begin
      if vIsDrawOnBitMap then
        SetPixelV(SelectionMatrix.Canvas.Handle, vPts[0].X, vPts[0].Y, SelectionMatrix.Canvas.Pen.Color);
      if vIsDrawOnCanvas then
        SetPixelV(FCanvas.Handle, vPts[0].X, vPts[0].Y, FCanvas.Pen.Color);
    end
    else
    begin
      vPts[4] := vPts[0];
      if vIsDrawOnBitMap then
        Windows.Polyline(SelectionMatrix.Canvas.Handle, PPoint(@vPts)^, 5);
      if vIsDrawOnCanvas then
        Windows.Polyline(FCanvas.Handle, PPoint(@vPts)^, 5);
    end;
  end;

begin
  vIsDrawOnBitMap := IsDrawOnBitMap;
  vIsDrawOnCanvas := IsDrawOnCanvas;
//Self := Drawing;
  ApplyPen(Sender);
  if vLine.ZThick = 0 then
  begin
    if FReady and vLine.Lines.IsSolid then
    begin
      if IsEqualPoints(FIPoints[0], FIPoints[1]) then
      begin
        if vIsDrawOnBitMap then
        begin
          AddSelectionMatrix(Sender);
          SetPixelV(SelectionMatrix.Canvas.Handle,FIPoints[0].X, FIPoints[0].Y, SelectionMatrix.Canvas.Pen.Color);
        end;
        if vIsDrawOnCanvas then
          SetPixelV(FCanvas.Handle,FIPoints[0].X, FIPoints[0].Y, FCanvas.Pen.Color);
      end
      else
      begin
        if vIsDrawOnBitMap then
        begin
          AddSelectionMatrix(Sender);
          Polyline(SelectionMatrix.Canvas.Handle, FIPoints, 2);
        end;
        if vIsDrawOnCanvas then
          Polyline(FCanvas.Handle, FIPoints, 2);
      end;
    end
    else
    begin
      if vLine.Lines.IsSolid then
       DrawPointsListByPolyline(Sender, vLine.DottedSingPts)
      else
        DrawPointsListByPolyPolyline(Sender, vLine.DottedSingPts);
    end;
  end
  else
  begin
    FIntPoints.Count := 0;
    if vIsDrawOnBitMap then
      AddSelectionMatrix(Sender);
    if vLine.Lines.IsSolid then
      DrawLineAndZTick(@vLine.Point, @vLine.Point1)
    else
    begin
      I := 0;
      Cnt := (vLine.DottedSingPts.Count shr 1) shl 1;
      while I < Cnt do
      begin
        DrawLineAndZTick(vLine.DottedSingPts[I], vLine.DottedSingPts[I + 1]);
        Inc(I, 2);
      end;
    end;
  end;
end;

procedure TsgDXFImage.DrawPoint(Sender: TObject);
var
  vPoint: TsgDXFPointAccess absolute Sender;
  vIsDrawOnBitMap, vIsDrawOnCanvas: Boolean;
  I, IE, J, Cnt, vCount: Integer;
  P, P2: TPoint;
  vPt: TFPoint;
begin
//Self := Drawing;
  FIntPoints.Count := 0;
  ApplyPen(Sender);
  vIsDrawOnBitMap := IsDrawOnBitMap;
  vIsDrawOnCanvas := IsDrawOnCanvas;
  if vIsDrawOnBitMap then
    AddSelectionMatrix(Sender);
  if vPoint.FPoints = nil then
  begin
    vPt := vPoint.Point;
    P := GetPoint(vPt);
    FIntPoints.Add(Pointer(P.X));
    FIntPoints.Add(Pointer(P.Y));
    if Abs(vPoint.ZThick) > fAccuracy then
    begin
      vPt := MakeFPoint(0, 0, vPoint.ZThick);
      if Extruded(vPoint.Extrusion) then
        DoExtrusion(vPt, vPoint.Extrusion);
      vPt.X := vPoint.Point.X + vPt.X;
      vPt.Y := vPoint.Point.Y + vPt.Y;
      vPt.Z := vPoint.Point.Z + vPt.Z;
      P2 := GetPoint(vPt);
      FIntPoints.Add(Pointer(P2.X + Integer(IsEqualPoints(P, P2))));
      FIntPoints.Add(Pointer(P2.Y));
    end
    else
    begin
      FIntPoints.Add(Pointer(P.X + 1));
      FIntPoints.Add(Pointer(P.Y));
    end;
    if vIsDrawOnBitMap then
      DrawPolyLine(SelectionMatrix.Canvas.Handle, FIntPoints);
    if vIsDrawOnCanvas then
      DrawPolyLine(FCanvas.Handle, FIntPoints);
    FIntPoints.Count := 0;
  end
  else
  begin
    I := 2;
    vCount := vPoint.FPoints.Count;
    while I < vCount do
    begin
      Cnt := Integer(vPoint.FPoints[I]);
      Inc(I);
      J := I;
      Inc(I, Cnt);
      while J < I do
      begin
        P := GetPoint(PFPoint(vPoint.FPoints[J])^);
        FIntPoints.Add(Pointer(P.X));
        FIntPoints.Add(Pointer(P.Y));
        Inc(J);
      end;
      if FIntPoints.Count = 1 then
      begin
        FIntPoints.Add(Pointer(Integer(FIntPoints[0]) + 1));
        FIntPoints.Add(FIntPoints[1]);
      end;
      if vIsDrawOnBitMap then
        DrawPolyLine(SelectionMatrix.Canvas.Handle, FIntPoints);
      if vIsDrawOnCanvas then
        DrawPolyLine(FCanvas.Handle, FIntPoints);
      FIntPoints.Count := 0;
    end;
    if Abs(vPoint.ZThick) > fAccuracy then
    begin
      vCount := (vPoint.FPoints.Count - 2) shr 1;
      I := 2;
      IE := I + vCount;
      while I < IE do
      begin
        Cnt := Integer(vPoint.FPoints[I]);
        Inc(I);
        J := I;
        Inc(I, Cnt);
        while J < I do
        begin
          P := GetPoint(PFPoint(vPoint.FPoints[J])^);
          FIntPoints.Add(Pointer(P.X));
          FIntPoints.Add(Pointer(P.Y));
          P := GetPoint(PFPoint(vPoint.FPoints[J + vCount])^);
          FIntPoints.Add(Pointer(P.X));
          FIntPoints.Add(Pointer(P.Y));
          Inc(J);
        end;
      end;
      if vIsDrawOnBitMap then
        DrawPolyPolyLine(SelectionMatrix.Canvas.Handle, FIntPoints);
      if vIsDrawOnCanvas then
        DrawPolyPolyLine(FCanvas.Handle, FIntPoints);
      FIntPoints.Count := 0;
    end;
  end;
end;

procedure TsgDXFImage.DrawPoly(Sender: TObject);
var
  PLine: TsgDXFPolyLine absolute Sender;

  procedure DrawPolygonMesh;
  var
    I, J, M, N, K, C: Integer;
    P: PInteger;
    Pt: TPoint;
    vPointsList: TList;
  begin
    vPointsList := PLine.DottedSingPts;
    if PLine.IsPolygonMesh then
    begin
      M := PLine.MeshM;
      N := PLine.MeshN;
    end
    else
    begin
      M := 2;
      N := vPointsList.Count shr 1;
    end;
    for I := 0 to vPointsList.Count - 1 do
    begin
      Pt := GetPoint(PFPoint(vPointsList[I])^);
      FPoly.Add(Pointer(Pt.X));
      FPoly.Add(Pointer(Pt.Y));
      if (PLine.Lines.IsSolid) and ((I + 1) mod N = 0) and PLine.IsMeshNClosed then
      begin
        FPoly.Add(FPoly[FPoly.Count - (N shl 1)]);
        FPoly.Add(FPoly[FPoly.Count - (N shl 1)]);// count changed
      end;
    end;
    if PLine.Lines.IsSolid or (PLine.IsPolygonMesh and not PLine.IsPolyZThickness)then
    begin
      K := FPoly.Count;
      for I := 0 to N - 1 do
      begin
        J := I shl 1;
        while J < K do
        begin
          FPoly.Add(FPoly[J]);
          FPoly.Add(FPoly[J + 1]);
          Inc(J, N shl 1 + 2 * Ord(PLine.IsMeshNClosed));
        end;
        if PLine.IsMeshMClosed then
        begin
          J := I shl 1;
          FPoly.Add(FPoly[J]);
          FPoly.Add(FPoly[J + 1]);
        end;
      end;
      J := FPoly.Count;
      for I := 0 to M - 1 do
        FPoly.Add(Pointer(N + Ord(PLine.IsMeshNClosed)));
      for I := 0 to N - 1 do
        FPoly.Add(Pointer(M + Ord(PLine.IsMeshMClosed)));
      K := M + N;
    end
    else
    begin
      if PLine.IsMeshNClosed or PLine.IsPolyZThickness then
      begin
        C := Round(vPointsList.Count / M);
        for J := 1 to M - 1 do
          for I := 0 to C - 1 do
          begin
            K := C * J + I;
            Pt := GetPoint(PFPoint(vPointsList[K])^);
            FPoly.Add(Pointer(Pt.X));
	          FPoly.Add(Pointer(Pt.Y));
            Dec(K, C);
            Pt := GetPoint(PFPoint(vPointsList[K])^);
            FPoly.Add(Pointer(Pt.X));
            FPoly.Add(Pointer(Pt.Y));
          end;
      end;
      J := FPoly.Count;
      K := Round(J / 4);
      for I := 1 to K do
        FPoly.Add(Pointer(2));
    end;
    P := PInteger(FPoly.List);
    Inc(P, J);
    if IsDrawOnBitMap then
    begin
      AddSelectionMatrix(Sender);
      PolyPolyline(SelectionMatrix.Canvas.Handle, FPoly.List^, P^, K);
    end;
    if IsDrawOnCanvas then
      PolyPolyline(FCanvas.Handle, FPoly.List^, P^, K);
  end;

  procedure DrawPolyFaceMesh;
  var
    I, J, Index, PrevCount: Integer;
    vPolyPoints: TList;
    Pt: TPoint;

    procedure SetClosed(AFlag: Boolean);
    begin
      if AFlag then
      begin
        FPoly.Add(Pointer(FPoly[PrevCount]));
        FPoly.Add(Pointer(FPoly[PrevCount + 1]));
      end;
    end;

    function GetVertexIndex(AItemIndex: Integer): Integer;
    begin
      Result := Integer(PLine.PolyFaceVertexIndexes.Items[AItemIndex]);
    end;

    procedure DoFace(ASubIndex: Integer);
      procedure DoFaceByVertex(AVertexIndex: Integer);
      begin
        Index := GetVertexIndex(AVertexIndex);
        if (Index < 0) and (Abs(Index) <= PLine.PolyPoints.Count) then
        begin
          Pt := GetPoint(PFPoint(PLine.PolyPoints[Abs(Index) - 1])^);
          FPoly.Add(Pointer(Pt.X));
          FPoly.Add(Pointer(Pt.Y));
        end;
        SetClosed((Index = 0) or (Index > PLine.PolyPoints.Count));
      end;
    begin
      DoFaceByVertex(I + ASubIndex);
      DoFaceByVertex(I);
    end;

  begin
    vPolyPoints := TList.Create;
    try
      I := 0;
      while I < PLine.PolyFaceVertexIndexes.Count do
      begin
        PrevCount := FPoly.Count;
        for J := 0 to 3 do
        begin
          Index := GetVertexIndex(I + J);
          if (Index >= 1) and (Index <= PLine.PolyPoints.Count) then
          begin
            Pt := GetPoint(PFPoint(PLine.PolyPoints[Index - 1])^);
            FPoly.Add(Pointer(Pt.X));
	          FPoly.Add(Pointer(Pt.Y));
          end;
        end;
        if FPoly.Count > PrevCount then
        begin
          J := (FPoly.Count - PrevCount) shr 1;
          if (J = 2) or (J = 3) then
            DoFace(J);
          SetClosed(J = 4);
          if (FPoly.Count - PrevCount) > 2 then// add the number of added points
            vPolyPoints.Add(Pointer((FPoly.Count - PrevCount) shr 1))
          else                                 // delete incorrect added point
          begin
            FPoly.Delete(PrevCount);
            FPoly.Delete(PrevCount);
          end;
        end;
        Inc(I, 4);
      end;
      //if PLine.Lines.IsSolid then
        if IsDrawOnBitMap then
        begin
          AddSelectionMatrix(Sender);
          PolyPolyline(SelectionMatrix.Canvas.Handle, FPoly.List^, PInteger(vPolyPoints.List)^, vPolyPoints.Count);
        end;
        if IsDrawOnCanvas then
          PolyPolyline(FCanvas.Handle, FPoly.List^, PInteger(vPolyPoints.List)^, vPolyPoints.Count);
    finally
      vPolyPoints.Free;
    end;
  end;

  procedure DrawArrows(Arrows: TList);
  var
    I, vPrevPFMode: Integer;
    Pt: TPoint;
  begin
    FPoly.Count := 0;
    FPoly.Capacity := Arrows.Count shl 1;
    for I := 0 to Arrows.Count - 1 do
    begin
      Pt := GetPoint(PFPoint(Arrows[I])^);
      FPoly.Add(Pointer(Pt.X));
      FPoly.Add(Pointer(Pt.Y));
    end;
    FCanvas.Brush.Style := bsSolid;
    FCanvas.Brush.Color := FCanvas.Pen.Color;
    ApplyBrush;
    vPrevPFMode := Windows.GetPolyFillMode(FCanvas.Handle);
    if IsDrawOnBitMap then
    begin
      AddSelectionMatrix(Sender);
      Windows.SetPolyFillMode(SelectionMatrix.Canvas.Handle, WINDING);
      I := 0;
      while I < FPoly.Count do
      begin
        Windows.Polygon(SelectionMatrix.Canvas.Handle, FPoly.List[I], 4);
        Inc(I, 8);
      end;
      Windows.SetPolyFillMode(SelectionMatrix.Canvas.Handle, vPrevPFMode);
      SelectionMatrix.Canvas.Brush.Style := bsClear;
    end;
    if IsDrawOnCanvas then
    begin
      Windows.SetPolyFillMode(FCanvas.Handle, WINDING);
      I := 0;
      while I < FPoly.Count do
      begin
        Windows.Polygon(FCanvas.Handle, FPoly.List[I], 4);
        Inc(I, 8);
      end;
      Windows.SetPolyFillMode(FCanvas.Handle, vPrevPFMode);
      FCanvas.Brush.Style := bsClear;
    end;
  end;

  procedure DrawPolyLineEntities(APolyLine: TsgDXFPolyline);
  var
    I: Integer;
    vEnt: TsgDXFEntity;
  begin
    // APolyLine.Iterate(Converter, DrawEntity);
    if APolyLine.PolyLineEntities = nil then
      Exit;
    for I := 0 to APolyLine.PolyLineEntities.Count - 1 do
    begin
      vEnt := TsgDXFEntity(APolyLine.PolyLineEntities[I]);
      if vEnt is TsgDXFArc then
        DrawArc(TsgDXFArc(APolyLine.PolyLineEntities[I]))
      else
    	if vEnt is TsgDXFLine then
    	  DrawLine(TsgDXFLine(APolyLine.PolyLineEntities[I]));
    end;
  end;

  procedure DrawPolyLineExt;
  var
    vIsDrawOnBitMap, vIsDrawOnCanvas: Boolean;
  begin
    vIsDrawOnBitMap := IsDrawOnBitMap;
    vIsDrawOnCanvas := IsDrawOnCanvas;
    if vIsDrawOnBitMap then
      BeginPath(SelectionMatrix.Canvas.Handle);
    if vIsDrawOnCanvas then
      BeginPath(FCanvas.Handle);
    if FReady and PLine.Lines.IsSolid then
    begin
      if vIsDrawOnBitMap then
      begin
        AddSelectionMatrix(Sender);
        PolyLine(SelectionMatrix.Canvas.Handle, FIPoints, FIndex);
      end;
      if vIsDrawOnCanvas then
        PolyLine(FCanvas.Handle, FIPoints, FIndex);
    end
    else
    begin
      if PLine.Lines.IsSolid then
        DrawPointsListByPolyline(Sender, PLine.DottedSingPts)
      else
        DrawPointsListByPolyPolyline(Sender, PLine.DottedSingPts);
    end;
    if vIsDrawOnBitMap then
    begin
      if PLine.Closed then CloseFigure(SelectionMatrix.Canvas.Handle);
      EndPath(SelectionMatrix.Canvas.Handle);
      StrokePath(SelectionMatrix.Canvas.Handle);
    end;
    if vIsDrawOnCanvas then
    begin
      if PLine.Closed then CloseFigure(FCanvas.Handle);
      EndPath(FCanvas.Handle);
      StrokePath(FCanvas.Handle);
    end;
  end;

begin
//Self := Drawing;
  FPoly.Count := 0;
  ApplyPen(PLine);
  if PLine.IsPolygonMesh or PLine.IsPolyZThickness then
  begin
    DrawPolygonMesh;
    Exit;
  end;
  if PLine.IsPolyFaceMesh then
  begin
    DrawPolyFaceMesh;
    Exit;
  end;

  if (FExtPenFlag <> 0) and (PLine.GetThickness <> 0) then
  begin// for non-AutoCAD formats
    DoScale2D(FDraw);
    FCanvas.Pen.Width := Round(Abs(PLine.GetThickness * FDraw.XScale));
    if FCanvas.Pen.Width = 0 then
      FCanvas.Pen.Width := 1;
  end;

 { if FUseWinEllipse and (not Converter.Is3D)
    and PLine.Lines.IsSolid and (Converter.VPort.X = 0)
      and (Converter.VPort.Y = 0) and (Converter.VPort.Z > 0) and (PLine.GlobalWidth = 0) then
        DrawPolyLineEntities(PLine)
  else }
  DrawPolyLineExt;
  if PLine.Arrows <> nil then
    DrawArrows(PLine.Arrows);
end;

procedure TsgDXFImage.DrawACISEntity(Sender: TObject);
begin
  // only for correct calling of  Assigned(E.OnDraw)
  // or for changes in future versions
end;

procedure TsgDXFImage.DrawSpline(Sender: TObject);
var
  vSpline: TsgDXFSpline absolute Sender;
begin
//Self := Drawing;
  FPoly.Count := 0;
  ApplyPen(vSpline);
  if vSpline.FitCount > vSpline.ControlCount then
  begin
    DrawPoly(vSpline);
    Exit;
  end;
  if vSpline.Lines.IsSolid then
    DrawPointsListByPolyline(Sender, vSpline.DottedSingPts)
  else
    DrawPointsListByPolyPolyline(Sender, vSpline.DottedSingPts);
end;

procedure TsgDXFImage.DrawSolid(Sender: TObject);
var
  FSolid: array [0..3] of TPoint;
begin
//Self := Drawing;
  ApplyPen(Sender);
  FCanvas.Pen.Width := 0;
  FCanvas.Brush.Style := bsSolid;
  FCanvas.Brush.Color := FCanvas.Pen.Color;
  if Sender is TsgDXFImageEnt then
    FCanvas.Brush.Style := bsClear
  else
    FCanvas.Brush.Style := bsSolid;
  if FReady then
  begin
    FSolid[0] := FIPoints[0];
    FSolid[1] := FIPoints[1];
    FSolid[2] := FIPoints[3];
    FSolid[3] := FIPoints[2];
  end
  else
  begin
    FSolid[0] := GetPoint(TsgDXFSolid(Sender).Point);
    FSolid[1] := GetPoint(TsgDXFSolid(Sender).Point1);
    FSolid[2] := GetPoint(TsgDXFSolid(Sender).Point3);
    FSolid[3] := GetPoint(TsgDXFSolid(Sender).Point2);
  end;
  if IsDrawOnBitMap then
  begin
    AddSelectionMatrix(Sender);
    SelectionMatrix.Canvas.Pen.Width := 0;
    SelectionMatrix.Canvas.Brush.Style := bsSolid;
    Polygon(SelectionMatrix.Canvas.Handle, FSolid[0], 4);
    SelectionMatrix.Canvas.Brush.Style := bsClear;
  end;
  if IsDrawOnCanvas then
  begin
    Polygon(FCanvas.Handle, FSolid[0], 4);
    FCanvas.Brush.Style := bsClear;
  end;
end;


procedure TsgDXFImage.DrawImage(Sender: TObject);
var
  vImageEnt: TsgDXFImageEntAccess absolute Sender;
  vPts: array [0..4] of TPoint;
  vAngle: Double;
  R: Integer;
{$IFDEF SG_USEGDIPLUS}
  graphics: TsgGDIPlusGraphics;
  vAttr: TsgGDIPlusImageAttributes;
  vH, vW: Integer;
{$ENDIF}

  function GetAngleByPoints(const ACenter, APoint: TFPoint): Double;
  var
    vKatetX, vKatetY: Double;
    vCmp: TPoint;
  begin
    vKatetX := (APoint.X - ACenter.X);
    vKatetY := -(APoint.Y - ACenter.Y);
    vCmp.X := Integer(vKatetX < 0);
    vCmp.Y := Integer(vKatetY < 0);
    vKatetX := Abs(vKatetX);
    vKatetY := Abs(vKatetY);
    if vKatetX < fAccuracy then
      Result := 90 + 180 * vCmp.Y
    else
    begin
      Result := f180DividedByPi * ArcTan(vKatetY / vKatetX);
      case vCmp.X shl 1 + vCmp.Y of
        1:  Result := 360 - Result;
        2:  Result := 180 - Result;
        3:  Result := 180 + Result;
      end;
    end;
  end;

begin
//Self := Drawing;
  vImageEnt.FindPicture(FConverter);
  if vImageEnt.Picture = nil then Exit;
  vPts[0] := GetPoint(vImageEnt.Point);
  vPts[1] := GetPoint(vImageEnt.Point1);
  vPts[2] := GetPoint(vImageEnt.Point3);
  vPts[3] := GetPoint(vImageEnt.Point2);
  vPts[4] := vPts[0];
  if IsDrawOnBitMap and (vImageEnt.FFlag = 0) then
  begin
    AddSelectionMatrix(Sender);
    SelectionMatrix.Canvas.Brush.Style := bsSolid;
    Polygon(SelectionMatrix.Canvas.Handle, vPts, 4);
    SelectionMatrix.Canvas.Brush.Style := bsClear;
  end;
{$IFDEF SG_USEGDIPLUS}
  if FLibraryGDIPlusExists and bUseGDIPlusForRastImgRotate then
  begin
    if vImageEnt.FGDIPImage = nil then
      vImageEnt.GDIPCreate;
    if vImageEnt.FGDIPImage <> nil then
    begin
      vPts[4] := vPts[0];
      vPts[0] := vPts[3];
      vPts[2] := vPts[4];
      Inc(vPts[1].X, vPts[0].X - vPts[2].X);
      Inc(vPts[1].Y, vPts[0].Y - vPts[2].Y);
      graphics := TsgGDIPlusGraphics.Create(FCanvas.Handle);
      try
        graphics.SetInterpolationMode(InterpolationModeNearestNeighbor);
        if (vImageEnt.Picture.Graphic is TsgBitMap) and (TsgBitmapAccess(vImageEnt.Picture.Graphic).FROP <> SRCCOPY) then
        begin
          vAttr := TsgGDIPlusImageAttributes.Create;
          try
            vAttr.SetColorKey(aclWhite, aclWhite, ColorAdjustTypeBitmap);
            vW := vImageEnt.Picture.Graphic.Width;
            vH := vImageEnt.Picture.Graphic.Height;
            graphics.DrawImage(vImageEnt.FGDIPImage, PsgGPoint(@vPts[0]), 3, 0, 0, vW, vH, vAttr);
          finally
            vAttr.Free;
          end;
        end
        else
          graphics.DrawImage(vImageEnt.FGDIPImage, PsgGPoint(@vPts[0]), 3);
      finally
        graphics.Free;
      end;
    end
    else
      FCanvas.Polyline(vPts);
  end
  else
{$ENDIF}
  begin
    if not (vImageEnt.GetAnimate or (vImageEnt.Picture.Graphic is TMetafile)) then
      vImageEnt.ChangeGraphic;
    vAngle := GetAngleByPoints(GetFPoint(vImageEnt.Point), GetFPoint(vImageEnt.Point1));
    R := (Round(vAngle - vImageEnt.Rotate) div 90) * 90;
    if R <> 0 then
    begin
      vImageEnt.DoRotate(R);
      vImageEnt.Rotate := vAngle;
    end;
    if ShowImages and IsEqual((Round(vImageEnt.Rotate) div 90) * 90, vImageEnt.Rotate) then
      FCanvas.StretchDraw(FIRect, vImageEnt.Picture.Graphic)
    else
      DrawSolid(Sender);
    if vImageEnt.IsMonoChrome and (BackgroundColor = clBlack) then
    begin
      PatBlt(FCanvas.Handle, FIRect.Left,FIRect.Top, FIRect.Right-FIRect.Left,
        FIRect.Bottom-FIRect.Top, DSTINVERT);
    end;
  end;
end;

procedure TsgDXFImage.FillFromFlat(FP: TsgFlatEntity);
var
  I: Integer;
  P: TPoint;
begin
  if FPoly.Capacity < FP.Points.Count then
    FPoly.Capacity := FP.Points.Count;
  FPoly.Count := 0;
  for I := 0 to FP.PCount-1 do
  begin
    P := GetPoint(FP.XY[I]);
    FPoly.Add(Pointer(P.X));
    FPoly.Add(Pointer(P.Y));
  end;
end;

procedure TsgDXFImage.DrawFlatPoly(Sender: TObject);
var
  FP: TsgFlatPoly absolute Sender;
  procedure DrawFlatPolyExt(const ACanvas: TCanvas);
  var
    I: Integer;
    P0: PPoint;
  begin
    P0 := PPoint(FPoly.List);
    for I := 0 to FP.Counts.Count-1 do
    begin
      Polyline(ACanvas.Handle, P0^, Integer(FP.Counts[I]));
      Inc(P0, Integer(FP.Counts[I]));
    end;
  end;
begin
//Self := Drawing;
  ApplyPen(Sender); //FCanvas.Pen.Width := Round(FP.GetThickness / FmmToPixelX);
  FillFromFlat(FP);
  if IsDrawOnBitMap then
  begin
    AddSelectionMatrix(Sender);
    DrawFlatPolyExt(SelectionMatrix.Canvas);
  end;
  if IsDrawOnCanvas then
    DrawFlatPolyExt(FCanvas);
end;

procedure TsgDXFImage.DrawFlatHatch(Sender: TObject);
var
  FH: TsgFlatHatch absolute Sender;
  procedure DrawHatchExt(const ACanvas: TCanvas);
  var
    PI: PInteger;
    PP: PPoint;
    C: Integer;
  begin
    PI := PInteger(FH.Counts.List);
    PP := PPoint(FPoly.List);
    while True do
    begin
      C := PI^;
      Inc(PI);
      if C = 0 then Exit;
      PolyPolygon(ACanvas.Handle, PP^, PI^, C);
      Inc(PI,C);
      C := PI^;
      Inc(PI);
      Inc(PP,C);
    end;
  end;
begin
//Self := Drawing;
  ApplyPen(Sender);
  FCanvas.Brush.Color := FCanvas.Pen.Color;
  FCanvas.Pen.Width := 0;
  FillFromFlat(FH);
  if IsDrawOnBitMap then
  begin
    AddSelectionMatrix(Sender);
    DrawHatchExt(SelectionMatrix.Canvas);
  end;
  if IsDrawOnCanvas then
     DrawHatchExt(FCanvas);
end;

procedure TsgDXFImage.DrawText(Sender: TObject);
const
  cnstMaxTextHeight = 8192;// Solution of the big fonts GDI-problem
var
  P: TFPoint;
  S: string;
  vSy, vScale, vLeft, vBottom, vRight, vTop: Double;
  C: TColor;
  vAbove, vBelow: Integer;
  vRect: TRect;
  vBox: TFRect;
  vP, vP1: TPoint;
  vList: TList;
  vVertex1, vVertex2: PsgSHXVertex;
  vMatrix: TFMatrix;
  vTV1, vTV2 : TsgSHXVertex;
  vSender: TsgDXFText;
  vPrevDraw: TsgCADIterate;
  I: Integer;
  vIsDrawOnCanvas, vIsDrawOnBitMap: Boolean;

  procedure TxtOut;
  var
    vTextGlyph: TsgTextGlyph;
    vPts: array[0..3] of TFPoint;
    vIndex: Integer;
    vUnicodeText: WideString;
{$IFNDEF SGDEL_6}
    vTextFlags: Integer;
{$ENDIF}

    procedure DrawTextExt;
    var
      vGlyphBox: TFRect;
      vPtsList: TList;
      vWidth, vDeltaWidth: Double;
      I: Integer;

      procedure InitPts(AIndex: Integer; ABox: PFRect);
      var
        vWidthCur: Integer;
        Pt1, Pt2: TFPoint;
      begin
        Pt1 := PtXMat(MakeFPoint(ABox.Left, ABox.Bottom, ABox.Z1), vMatrix);
        Pt2 := PtXMat(ABox.BottomRight, vMatrix);
        vWidth := DistanceF(Pt1, Pt2);
        vWidthCur := Floor(vWidth);
        vDeltaWidth := vDeltaWidth + vWidth - vWidthCur;
        if vDeltaWidth > 0.99 then
        begin
          Inc(vWidthCur);
          vDeltaWidth := vDeltaWidth - 1;
        end;
        vPtsList[AIndex] := Pointer(vWidthCur);
      end;

    begin
      vRect.TopLeft := GetPoint(vBox.TopLeft);
      vRect.BottomRight := GetPoint(vBox.BottomRight);
      if (Length(vUnicodeText) > 0) and (Integer(vUnicodeText[1]) shr 8 >= $50) then
        FCanvas.Font.Height := Round(vRect.Top - vRect.Bottom);
      vPtsList := TList.Create;
      try
        vDeltaWidth := 0;
        if Length(vUnicodeText) = 0 then
        begin
          vPtsList.Count := Length(S);
          for I := 1 to vPtsList.Count do
          begin
            vGlyphBox := vTextGlyph.GetBox(S[I], @cnstIdentityMat);
            InitPts(I - 1, @vGlyphBox);
          end;
{$IFNDEF SGDEL_6}
          ExtTextOut(FCanvas.Handle, Round(P.X), Round(P.Y), vTextFlags,
            @vRect, PChar(S), Length(S), @vPtsList.List[0]);
{$ELSE}
          ExtTextOut(FCanvas.Handle, Round(P.X), Round(P.Y), FCanvas.TextFlags,
            @vRect, PChar(S), Length(S), @vPtsList.List[0]);
{$ENDIF}
        end
        else
        begin
          vPtsList.Count := Length(vUnicodeText);
          for I := 1 to vPtsList.Count do
          begin
            vGlyphBox := vTextGlyph.GetBoxW('', vUnicodeText[I], @cnstIdentityMat);
            InitPts(I - 1, @vGlyphBox);
          end;
{$IFNDEF SGDEL_6}
          ExtTextOutW(FCanvas.Handle, Round(P.X), Round(P.Y), vTextFlags,
             @vRect, PWideChar(vUnicodeText), Length(vUnicodeText), @vPtsList.List[0]);
{$ELSE}
          ExtTextOutW(FCanvas.Handle, Round(P.X), Round(P.Y), FCanvas.TextFlags,
             @vRect, PWideChar(vUnicodeText), Length(vUnicodeText), @vPtsList.List[0]);
{$ENDIF}
        end;
      finally
        vPtsList.Free;
      end;
    end;

    function IsRotatedMatrix(const M: TFMatrix): Boolean;
    var
      I,J: Integer;
      K: Double;
    begin
      Result := (M[0,0] <= fAccuracy) or (M[1,1] >= fAccuracy);
      if Result then Exit;
      if Abs(M[1,1]) > fAccuracy then
      begin
        K := Abs(M[0,0] / M[1,1]);
        Result := Abs(K - 1) > 0.15;
      end
      else
        Result := Abs(M[0,0]) > fAccuracy;
      if Result then Exit;
      for I := 0 to 2 do
      begin
        for J := 0 to 2 do
        begin
          if I <> J then
          begin
            Result := Abs(M[I,J]) > fAccuracy;
            if Result then Exit;
          end;
        end;
      end;
    end;

    function IsHasZKoord: Boolean;
    const
      Illegal = -$5555 * 65536.0 * 65536.0;
      function IsNotIllegalFPoint(const AP: TFPoint): Boolean;
      begin
        Result := (AP.X <> Illegal) and (AP.Y <> Illegal);
      end;
    begin
      Result := (vSender.Point.Z + Integer(IsNotIllegalFPoint(vSender.Point1)) * vSender.Point1.Z) <> 0;
    end;

  begin
{$IFNDEF SGDEL_6}
   vTextFlags := 0;
{$ELSE}
   FCanvas.TextFlags := 0;
{$ENDIF}
    if Win32Platform = VER_PLATFORM_WIN32_NT then
      vUnicodeText := vSender.UnicodeText
    else
      vUnicodeText := '';
    SetTextAlign(FCanvas.Handle, TA_BASELINE);
    FCanvas.Brush.Style := bsClear;
    if not FExportToDXFMode then
      vIndex := ContainerOfTextGlyphs.IndexOf(vSender.Font.Name, FCanvas.Font.Style)
    else // only for export to DXF mode (not for use in future versions)
      vIndex := -1;
    if vIndex > -1 then
    begin
      vTextGlyph := ContainerOfTextGlyphs.TextGlyph[vIndex];
      vMatrix := MatXMat(vSender.GetMatrix, FDraw.Matrix);
      if FCanvas.Font.Height < 2 then
      begin
        if IsBadRect(vBox) then Exit;
        vBox := vTextGlyph.GetBoxW(S, vUnicodeText, @cnstIdentityMat);
        vPts[0] := PtXMat(vBox.TopLeft, vMatrix);
        vPts[1] := PtXMat(MakeFPoint(vBox.Right, vBox.Top, 0), vMatrix);
        vPts[2] := PtXMat(vBox.BottomRight, vMatrix);
        vPts[3] := PtXMat(MakeFPoint(vBox.Left, vBox.Bottom, 0), vMatrix);
        if vIsDrawOnBitMap then
        begin
          SelectionMatrix.Canvas.Polygon([Point(Round(vPts[0].X), Round(vPts[0].Y)),
            Point(Round(vPts[1].X), Round(vPts[1].Y)),
            Point(Round(vPts[2].X), Round(vPts[2].Y)),
            Point(Round(vPts[3].X), Round(vPts[3].Y))]);
         end;
        if vIsDrawOnCanvas then
        begin
          FCanvas.Brush.Color := FCanvas.Font.Color;
          FCanvas.Polygon([Point(Round(vPts[0].X), Round(vPts[0].Y)),
            Point(Round(vPts[1].X), Round(vPts[1].Y)),
            Point(Round(vPts[2].X), Round(vPts[2].Y)),
            Point(Round(vPts[3].X), Round(vPts[3].Y))]);
        end;
      end
      else
      begin
        vSender.Font.Height := Abs(Round(vTextGlyph.HKoef * vSender.Height * FHCoef));
        vSender.Font.Width := 0;//Abs(Round(0.64 * vSender.Height * FDraw.XScale));
        vSender.Font.HandleNeeded;
        C := FCanvas.Font.Color;
        FCanvas.Font := vSender.Font;
        FCanvas.Font.Color := C;
        ApplyText;
        if vIsDrawOnBitMap then
          vTextGlyph.DrawTextExtW(SelectionMatrix.Canvas, vSender.Font.Style, S, vUnicodeText, @vMatrix);
        if vIsDrawOnCanvas then
        begin
          if (vSender.UpsideDown) or (vSender.Backward) or (Abs(vSender.Scale - 1) > fAccuracy) or
             IsHasZKoord or IsRotatedMatrix(vMatrix) or (vSender.Font.Height > cnstMaxTextHeight) then
            vTextGlyph.DrawTextExtW(FCanvas, vSender.Font.Style, S, vUnicodeText, @vMatrix)
          else
            DrawTextExt;
        end;
      end;
    end
    else
    begin
      if (FCanvas.Font.Height < 2) and not FExportToDXFMode then
      begin
        if IsBadRect(vBox) then Exit;
        vRect.TopLeft := GetPoint(vBox.TopLeft);
        vRect.BottomRight := GetPoint(vBox.BottomRight);
        if vRect.Left > vRect.Right then
          SwapInts(vRect.Left, vRect.Right);
        if vRect.Top > vRect.Bottom then
          SwapInts(vRect.Top, vRect.Bottom);
        vP := Point(Round(P.X), Round(P.Y));
        if vIsDrawOnBitMap then
        begin
          if vSender.Font.Escapement = 0 then
            SelectionMatrix.Canvas.Rectangle(vP.X, vP.Y, vP.X + (vRect.Right-vRect.Left) , vP.Y + (vRect.Bottom-vRect.Top))
          else
          begin
            SelectionMatrix.Canvas.MoveTo(vP.X, vP.Y);
            SelectionMatrix.Canvas.LineTo(Round(vP.X + (vRect.Right-vRect.Left)*Cos(vSender.Font.Escapement*0.1)),
              Round(vP.Y - (vRect.Bottom-vRect.Top)*Sin(vSender.Font.Escapement*0.1)));
          end;
        end;
        if vIsDrawOnCanvas then
        begin
          if vSender.Font.Escapement = 0 then
            FCanvas.Rectangle(vP.X, vP.Y, vP.X + (vRect.Right-vRect.Left) , vP.Y + (vRect.Bottom-vRect.Top))
          else
          begin
            FCanvas.MoveTo(vP.X, vP.Y);
            FCanvas.LineTo(Round(vP.X + (vRect.Right-vRect.Left)*Cos(vSender.Font.Escapement*0.1)),
              Round(vP.Y - (vRect.Bottom-vRect.Top)*Sin(vSender.Font.Escapement*0.1)));
          end;
        end;
      end
      else
      begin
        if vIsDrawOnBitMap then
        begin
          if Length(vUnicodeText) = 0 then
            TextOut(SelectionMatrix.Canvas.Handle, Round(P.X), Round(P.Y), PChar(S), Length(S))
          else
            TextOutW(SelectionMatrix.Canvas.Handle, Round(P.X), Round(P.Y), PWideChar(vUnicodeText), Length(vUnicodeText));
        end;
        if vIsDrawOnCanvas then
        begin
          if Length(vUnicodeText) = 0 then
            TextOut(FCanvas.Handle, Round(P.X), Round(P.Y), PChar(S), Length(S))
          else
            TextOutW(FCanvas.Handle, Round(P.X), Round(P.Y), PWideChar(vUnicodeText), Length(vUnicodeText));
        end;
      end;
    end;
  end;

  procedure GetSHXLines(const AStr: string; const AWStr: WideString);
  var
    S, W: string;
  begin
    S := '';
    W := '';
    if AStr <> '' then
    begin
      if fmUnderline in vSender.Font.Style then S := #1;
      if fmStrikeOut in vSender.Font.Style then S := S + #3;
    end
    else if AWStr <> '' then
    begin
      if fmUnderline in vSender.Font.Style then W := #1;
      if fmStrikeOut in vSender.Font.Style then W := W + #3;
    end;
    if vSender.SHXFont <> '' then
      DrawSHXText(SHXFontsProc, vSender.SHXFont,S + AStr,W + AWStr,
        False, vSender.Backward, vList, vAbove, vBelow, vLeft, vBottom, vRight, vTop)
    else
      GetSHXText(SHXFontsProc, vSender.Style.Name,S + AStr,
       W + AWStr, vList, vAbove, vBelow, vLeft, vBottom, vRight, vTop);
  end;

  function GetSHXPoint(const P: TFPoint): TPoint;
  begin
    Result.X := Round(P.X * vMatrix[0, 0] + P.Y * vMatrix[1, 0] +
      P.Z * vMatrix[2, 0] + vMatrix[3, 0]);
    Result.Y := Round(P.X * vMatrix[0, 1] + P.Y * vMatrix[1, 1] +
      P.Z * vMatrix[2, 1] + vMatrix[3, 1]);
  end;

  procedure DrawBulge(PV1, PV2: PsgSHXVertex);
  var
    X0, Y0, X1, Y1, X2, Y2, A, A1, BT: Double;
    I: Integer;
    SinA, CosA: Extended;
    vP: TPoint;
  begin
    A := ArcTan(PV1^.Bulge) * 2;
    A1 := A / (iDefaultNumberOfCircleParts) * 2;
    SinCos(A1, SinA, CosA);
    BT := (1 / PV1^.Bulge - PV1^.Bulge)/2;
    X0 := ((PV1^.X + PV2^.X) - BT * (PV1^.Y - PV2^.Y)) / 2;
    Y0 := ((PV1^.Y + PV2^.Y) + BT * (PV1^.X - PV2^.X)) / 2;
    X1 := PV2^.X;
    Y1 := PV2^.Y;
    for I := 0 to iDefaultNumberOfCircleParts - 1 do
    begin
      X2 := X0 + (X1 - X0) * CosA - (Y1 - Y0) * SinA;
      Y2 := Y0 + (X1 - X0) * SinA + (Y1 - Y0) * CosA;
      vP := GetSHXPoint(MakeFPoint(X2  * vSy, Y2* vSy , 0));
      X1 := X2;
      Y1 := Y2;
      if vIsDrawOnBitMap then
        SelectionMatrix.Canvas.LineTo(vP.X, vP.Y);
      if vIsDrawOnCanvas then
        FCanvas.LineTo(vP.X, vP.Y);
    end;
  end;
  
begin
//Self := Drawing;
  if not FTextVisible then
    Exit;
  vSender := TsgDXFText(Sender);
  vIsDrawOnBitMap := IsDrawOnBitMap;
  vIsDrawOnCanvas := IsDrawOnCanvas;
  if vIsDrawOnBitMap then
  begin
    AddSelectionMatrix(Sender);
    SelectionMatrix.Canvas.Font.Color := SelectionMatrix.Canvas.Pen.Color;
  end;
  vPrevDraw := FDraw;
  try
    P := PtXMat(vSender.StartPoint, FDraw.Matrix);
    S := vSender.Text;
    vScale := vSender.Scale;
    vBox := vSender.Box;
    if (vScale = 0) or ((Trim(S) = '') and (Trim(vSender.UnicodeText) = '')) then
      Exit;
    vSender.Font.PixelsPerInch := FCanvas.Font.PixelsPerInch;
    if (Pos('ˆ',S) > 0) or (Pos('±',S) > 0) or (Pos('°',S) > 0) then
      vSender.Font.Charset := DEFAULT_CHARSET
    else
      vSender.Font.Charset := Charset;
    DoScale2D(FDraw);
    if FDraw.XScale = 0 then Exit;
    vSender.Font.Height :=  Abs(Round(fWinTextHeightFactor * Abs(vSender.Height) * FHCoef));
    vSender.Font.Width := Abs(Round(0.64 * Abs(vSender.Height) * vScale * FHCoef));
    if vSender.Font.Height = 0 then
      vSender.Font.Height := 1;
    if Sender is TsgDXFAttdef then
      vSender.Font.Escapement := Round(10 * vSender.Rotation)
    else
      vSender.Font.Escapement := Round(10 * (vSender.Rotation - FAngle));

    vSender.Font.HandleNeeded;
    C := FCanvas.Font.Color;
    FCanvas.Font := vSender.Font;
    FCanvas.Font.Color := C;
    ApplyText;

    if bUseSHXFonts and (not vSender.WinFont) and vSender.IsSHXFont then
    begin
      vList := TList.Create;
      try
        GetSHXLines(vSender.SHXText, vSender.SHXUnicodeText);
        if vList.Count > 0 then
        begin
          vSy := vSender.Height / vAbove;
          vMatrix := MatXMat(vSender.SHXMatrix, FDraw.Matrix);
          vVertex1 := GetVertex(vList, 0, vSy);
          vVertex2 := nil;
          vP1 := GetSHXPoint(MakeFPoint(vVertex1^.X,  vVertex1^.Y , 0));
          FCanvas.Pen.Color := FCanvas.Font.Color;
          ApplyPen(Sender);
          if vIsDrawOnBitMap then
            SelectionMatrix.Canvas.MoveTo(vP1.X, vP1.Y);
          if vIsDrawOnCanvas then
            FCanvas.MoveTo(vP1.X, vP1.Y);
          for I := 2 to vList.Count do
          begin
            vTV2 := PsgSHXVertex(vList[I - 1])^;
            vVertex2 := GetVertex(vList, I - 1, vSy);
            vP1 := GetSHXPoint(MakeFPoint(vVertex2^.X, vVertex2^.Y, 0));
            if not vVertex2^.PenDown then
            begin
              if vIsDrawOnBitMap then
                SelectionMatrix.Canvas.MoveTo(vP1.X, vP1.Y);
              if vIsDrawOnCanvas then
                FCanvas.MoveTo(vP1.X, vP1.Y)
            end
            else
            begin
              if vVertex2^.Bulge = 0 then
              begin
                if vIsDrawOnBitMap then
                  SelectionMatrix.Canvas.LineTo(vP1.X, vP1.Y);
                if vIsDrawOnCanvas then
                  FCanvas.LineTo(vP1.X, vP1.Y);
              end
              else
                DrawBulge(@vTV2, @vTV1);
             end;
            Dispose(vVertex1);
            vVertex1 := vVertex2;
            vTV1 := vTV2;
          end;
          if Assigned(vVertex2) then Dispose(vVertex2);
        end
        else
          TxtOut;
      finally
        vList.Free;
      end;
    end
    else
      TxtOut;
  finally
    FDraw := vPrevDraw;
  end;
end;

procedure TsgDXFImage.EndRead(Sender: TObject);
begin
  if not Assigned(OnProgress) then
    Exit;
  DoProgress(psEnding);
  FMsg := sLoadEntities;
end;

procedure TsgDXFImage.EnterInsert(Sender: TObject);
var
  Ins: TsgDXFInsert absolute Sender;
begin
  if FOnInsert = Sender then
    FOnInsertMode := False;
  if (Ins is TsgCADClipInsert) then
  begin
    if IsDrawOnBitMap then
      SelectClipRgn(SelectionMatrix.Canvas.Handle, FClipRegion);
    if {$IFDEF SGDEL_4}(not FSnapOnlyIterate) and{$ENDIF} IsDrawOnCanvas then
      SelectClipRgn(FCanvas.Handle, FClipRegion);
  end;
end;

procedure TsgDXFImage.EnterViewport(Sender: TObject);
begin
  if FViewPortCanvasParams <> nil then
  begin
    DeleteObject(FViewPortRegion);
    RestoreDC(FCanvas.Handle, FViewPortCanvasParams^.HDC);
    FCanvas.Brush := FViewPortCanvasParams^.CanvasParams.Brush;
    FCanvas.Font := FViewPortCanvasParams^.CanvasParams.Font;
    FCanvas.Pen := FViewPortCanvasParams^.CanvasParams.Pen;
    FViewPortCanvasParams^.CanvasParams.Brush.Free;
    FViewPortCanvasParams^.CanvasParams.Font.Free;
    FViewPortCanvasParams^.CanvasParams.Pen.Free;
    Dispose(FViewPortCanvasParams);
    FViewPortCanvasParams := nil;
  end;
end;

procedure TsgDXFImage.EnterXRef(Sender: TObject);
begin
  FSHXFontsProc := GetSHXFontsProc;
  FGetSelectionMatrixModeProc := GetSelectionMatrixProc;
  FSetSelectionMatrixModeProc := SetSelectionMatrixProc;  
end;

procedure TsgDXFImage.EntityCreated(Sender: TObject);
// Called from Converter after each entity is loaded from DXF
// In the previous versions a drawing procedure was assigned to the entity here
begin
  // SetDraw(TsgDXFEntity(Sender));
end;

function TsgDXFImage.GetBlock(Index: Integer): TsgDXFBlock;
begin
  Result := FConverter.Blocks[Index];
end;

function TsgDXFImage.GetEntity(Index: Integer): TsgDXFEntity;
begin
  Result := FConverter.Entities[Index];
end;

function TsgDXFImage.GetIs3D: Boolean;
begin
  Result := Converter.Is3D;
end;

function TsgDXFImage.GetIsLoading: Boolean;
begin
  Result := Loading <> nil;
end;

function TsgDXFImage.GetLayout(Index: Integer): TsgDXFLayout;
begin
  Result := FConverter.Layouts[Index];
end;

function TsgDXFImage.GetLayoutsCount: Integer;
begin
  Result := FConverter.LayoutsCount;
end;

function TsgDXFImage.GetLineWeightScale: TsgFloat;
begin
  Result := FLineWeightScale;
end;

function TsgDXFImage.GetScale: TFPoint;
begin
  Result := FScale;
end;

function TsgDXFImage.GetOwnSource: Boolean;
begin
  Result := Converter.OwnSource;
end;

function TsgDXFImage.GetRect(const ARect: TFRect): TRect;
  procedure ExpRect(const X, Y, Z: TsgFloat);
  begin
    ExpandRect(Result, GetPoint(MakeFPoint(X, Y, Z)));
  end;
begin
  Result := Classes.Rect(MaxInt, MaxInt, -MaxInt, -MaxInt);
  ExpRect(ARect.Left, ARect.Top, ARect.Z1);
  ExpRect(ARect.Left, ARect.Top, ARect.Z2);
  ExpRect(ARect.Left, ARect.Bottom, ARect.Z1);
  ExpRect(ARect.Left, ARect.Bottom, ARect.Z2);
  ExpRect(ARect.Right, ARect.Top, ARect.Z1);
  ExpRect(ARect.Right, ARect.Top, ARect.Z2);
  ExpRect(ARect.Right, ARect.Bottom, ARect.Z1);
  ExpRect(ARect.Right, ARect.Bottom, ARect.Z2);
end;

procedure TsgDXFImage.SetOwnSource(Value: Boolean);
begin
  Converter.OwnSource := Value;
end;

procedure TsgDXFImage.SetBackgroundColor(Value: TColor);
begin
  if FBackgroundColor <> Value then
  begin
    FBackgroundColor := Value;
    Changed(Self);
  end;
end;

procedure TsgDXFImage.SetCharset(Value: TFontCharset);
begin
  if Value <> Charset then
  begin
    FCharset := Value;
    Changed(Self);
  end;
end;

procedure TsgDXFImage.SetDefaultColor(Value: TColor);
begin
  if FDefaultColor <> Value then
  begin
    FDefaultColor := Value;
    Changed(Self);
  end;
end;

function TsgDXFImage.DoDraw(Entity: TsgDXFEntity): Integer;
begin
  Result := 0;
  case Entity.EntType of
    ceLine:              DrawLine(Entity);
    cePoint:             DrawPoint(Entity);
    ceSolid:             DrawSolid(Entity);
    ceCircle:            DrawCircle(Entity);
    ceArc, ceEllipse:    DrawArc(Entity);
    cePolyline,
      cePath:            DrawPoly(Entity);
    ceSpline:            DrawSpline(Entity);
    ceLeader:            DrawLeader(Entity);
    ceDimension:         Result := DrawDimension(Entity);
    ceInsert,
      ceMText:           Result := DrawInsert(Entity);
    ceText,
      ceAttdef,
      ceAttrib:          DrawText(Entity);
    ce3dFace:            DrawFace(Entity);
    cePolyPolygon,
      ceGradient,
      ceGradientPolygon,
      ceCurvePolygon,
      ceHatch:           DrawHatch(Entity);
    ceImageEnt:          DrawImage(Entity);
    ceViewport:          DrawViewPort(Entity);
    ceRegion,
      ceBody, ce3DSolid: DrawACISEntity(Entity);
    ceOle2Frame:         DrawOle2Frame(Entity);
    ceFlatPoly:          DrawFlatPoly(Entity);
    ceFlatHatch:         DrawFlatHatch(Entity);
    ceXRef:              DrawXRef(Entity);
  end;
end;

function TsgDXFImage.DoFinish(Entity: TsgDXFEntity): Integer;
begin
  Result := 0;
  case Entity.EntType of
    ceDimension, ceInsert,
      ceMText:             EnterInsert(Entity);
    ceViewport:            EnterViewport(Entity);
    ceXRef:                EnterXRef(Entity);
  end;
end;

procedure TsgDXFImage.SetDrawingBox(const ABox: TFRect);
begin
  FDrawingBox := ABox;
  if IsBadRect(FDrawingBox) then
    SetExtentsParameters(FCurrentLayout.Box, FCurrentLayout.CADSpace <> csUndefined)
  else
    SetExtentsParameters(FDrawingBox, True);
  Changed(Self);
end;

procedure TsgDXFImage.SetDrawMode(Value: TsgDXFDrawMode);
begin
  if Value <> FDrawMode then
  begin
    FDrawMode := Value;
    Changed(Self);
  end;
end;

procedure TsgDXFImage.SetIs3D(Value: Boolean);
begin
  if Value <> Is3D then
  begin
    Converter.Is3D := Value;
    if FCurrentLayout <> nil then
      SetCurrentLayout(FCurrentLayout);
  end;
end;

procedure TsgDXFImage.SetIsShowBackground(Value: Boolean);
begin
  if FIsShowBackground <> Value then
    FIsShowBackground := Value;
end;

procedure TsgDXFImage.SetIsShowLineWeight(Value: Boolean);
begin
  if FIsShowLineWeight <> Value then
  begin
    FIsShowLineWeight := Value;
    Changed(Self);
  end;
end;

procedure TsgDXFImage.SetIsWithoutBorder(Value: Boolean);
begin
  FIsWithoutBorder := Value;
  //if (Converter <> nil) and (Converter.Count > 0) then
  if FCurrentLayout <> nil then
    SetCurrentLayout(FCurrentLayout);
end;

procedure TsgDXFImage.SetLineScaled(Value: Boolean);
begin
  FLineScaled := Value;
end;

procedure TsgDXFImage.SetStretch(Value: Boolean);
begin
  if Value <> FStretch then
  begin
    FStretch := Value;
    Changed(Self);
  end;
end;

procedure TsgDXFImage.SetLineWeightScale(const Value: TsgFloat);
begin
  FLineWeightScale := Value;
end;

procedure TsgDXFImage.SetUseWinEllipse(Value: Boolean);
begin
  if Value <> FUseWinEllipse then
  begin
    FUseWinEllipse := Value;
    Changed(Self);
  end;
end;

procedure TsgDXFImage.SetShowImages(Value: Boolean);
begin
  if Value <> FShowImages then
  begin
    FShowImages := Value;
    Changed(Self);
  end;
end;

procedure TsgDXFImage.SetDimensionsVisible(AVisible: Boolean);
var
  I: Integer;
begin
  if (FDimensionsVisible <> AVisible) then
  begin
    FDimensionsVisible := AVisible;
    if Assigned(Converter) then
      for I := 0 to Converter.XRefs.Count - 1 do
        TsgDXFImage(TsgDXFXRef(Converter.XRefs.Items[I]).CADImage).DimensionsVisible := AVisible;
    GetExtents;
  end;
end;

procedure TsgDXFImage.SetTextVisible(AVisible: Boolean);
var
  I: Integer;
begin
  if (FTextVisible <> AVisible) then
  begin
    FTextVisible := AVisible;
    if Assigned(Converter) then
      for I := 0 to Converter.XRefs.Count - 1 do
        TsgDXFImage(TsgDXFXRef(Converter.XRefs.Items[I]).CADImage).TextVisible := AVisible;
    GetExtents;
  end;
end;

procedure TsgDXFImage.StopLoading;
begin
  FConverter.StopLoading;
end;

procedure TsgDXFImage.DrawOle2Frame(Sender: TObject);
var
  F: TsgDXFOle2Frame absolute Sender;
  R: TRect;
  Pt, Pt1: TPoint;
  vBrushStyle: TBrushStyle;
begin
  if F.OleObject = nil then Exit;
//Self := Drawing;
  Pt := GetPoint(F.Point);
  Pt1 := GetPoint(F.Point1);
  R := Rect(Pt.X, Pt.Y, Pt1.X, Pt1.Y);
  if IsDrawOnBitMap then
  begin
    AddSelectionMatrix(Sender);
    SelectionMatrix.Canvas.Brush.Style := bsSolid;
    SelectionMatrix.Canvas.FillRect(R);
    SelectionMatrix.Canvas.Brush.Style := bsClear;
  end;
  if IsDrawOnCanvas then
  begin
    vBrushStyle := FCanvas.Brush.Style;
    try
      FCanvas.Brush.Style := bsSolid;
      FCanvas.Brush.Color := clWindow;
      FCanvas.FillRect(R);
      OleDraw(F.OleObject, F.Aspect, FCanvas.Handle, R);
    finally
      FCanvas.Brush.Style := vBrushStyle;
    end;
  end;
end;

procedure TsgDXFImage.DrawPointsListByPolyline(const AObj: TObject; const DottedSingPts: TList);
var
  I, vCnt: Integer;
  P, P0: TPoint;
  vDC, vDCMatrix: HDC;
  vColor, vColorMatrix: TColor;
  vIsDrawOnBitMap, vIsDrawOnCanvas: Boolean;
begin
  vIsDrawOnBitMap := IsDrawOnBitMap;
  if vIsDrawOnBitMap then
    AddSelectionMatrix(AObj);
  vIsDrawOnCanvas := IsDrawOnCanvas;
  FIntPoints.Count := 0;
  vDC := FCanvas.Handle;
  vDCMatrix := SelectionMatrix.Canvas.Handle;
  if DottedSingPts.Count = 2 then
  begin
    vColor := FCanvas.Pen.Color;
    vColorMatrix := SelectionMatrix.Canvas.Pen.Color;
    P0 := GetPoint(PFPoint(DottedSingPts[0])^);;
    P := GetPoint(PFPoint(DottedSingPts[1])^);
    if (P.X = P0.X) and (P.Y = P0.Y) then
    begin
      if vIsDrawOnBitMap then
         Windows.SetPixel(vDCMatrix, P0.X, P0.Y, vColorMatrix);
      if vIsDrawOnCanvas then
        Windows.SetPixel(vDC, P0.X, P0.Y, vColor);
    end
    else
    begin
      FIntPoints.Add(Pointer(P0.X));
      FIntPoints.Add(Pointer(P0.Y));
      FIntPoints.Add(Pointer(P.X));
      FIntPoints.Add(Pointer(P.Y));
    end;
  end
  else
  begin
    for I := 0 to DottedSingPts.Count - 1 do
    begin
      P := GetPoint(PFPoint(DottedSingPts[I])^);
      if FIntPoints.Count > 2 then
      begin
        if (abs(Integer(FIntPoints[FIntPoints.Count - 2]) - P.X) < 2) and
           (abs(Integer(FIntPoints[FIntPoints.Count - 1]) - P.Y) < 2) and
           (((Integer(FIntPoints[FIntPoints.Count - 4]) = P.X) or
          (Integer(FIntPoints[FIntPoints.Count - 4]) + 1 = P.X) or
          (Integer(FIntPoints[FIntPoints.Count - 4]) - 1 = P.X)) and
          ((Integer(FIntPoints[FIntPoints.Count - 3]) = P.Y) or
          (Integer(FIntPoints[FIntPoints.Count - 3]) + 1 = P.Y) or
          (Integer(FIntPoints[FIntPoints.Count - 3]) - 1 = P.Y)))  then
          Continue;
      end;
      FIntPoints.Add(Pointer(P.X));
      FIntPoints.Add(Pointer(P.Y));
    end;
  end;
  vCnt := FIntPoints.Count shr 1;
  if vCnt > 1 then
  begin
    if vIsDrawOnBitMap then
      Windows.Polyline(vDCMatrix, FIntPoints.List^, vCnt);
    if vIsDrawOnCanvas then
      Windows.Polyline(vDC, FIntPoints.List^, vCnt);
  end;
end;

procedure TsgDXFImage.DrawPointsListByPolyPolyline(const AObj: TObject; const DottedSingPts: TList);
var
  I, vCnt: Integer;
  vDC, vDCMatrix: HDC;
  vColor, vColorMatrix: TColor;
  vIsDrawOnBitMap, vIsDrawOnCanvas: Boolean;
  vPts: array [0..1] of TPoint;
begin
  FIntPoints.Count := 0;
  I := FCounts.Count;
  while I <= DottedSingPts.Count do
  begin
    FCounts.Add(Pointer(2));
    Inc(I);
  end;
  vIsDrawOnBitMap := IsDrawOnBitMap;
  if vIsDrawOnBitMap then
    AddSelectionMatrix(AObj);
  vIsDrawOnCanvas := IsDrawOnCanvas;
  vDC := FCanvas.Handle;
  vDCMatrix := SelectionMatrix.Canvas.Handle;
  vColor := FCanvas.Pen.Color;
  vColorMatrix := SelectionMatrix.Canvas.Pen.Color;
  vCnt := 0;
  I := 0;
  while I < DottedSingPts.Count do
  begin
    vPts[0] := GetPoint(PFPoint(DottedSingPts[I])^);
    vPts[1] := GetPoint(PFPoint(DottedSingPts[I + 1])^);
    Inc(I, 2);
    if (vPts[0].X = vPts[1].X) and (vPts[0].Y = vPts[1].Y) then
    begin
      if vIsDrawOnCanvas then
        Windows.SetPixel(vDCMatrix, vPts[0].X, vPts[0].Y, vColorMatrix);
      if vIsDrawOnCanvas then
        Windows.SetPixel(vDC, vPts[0].X, vPts[0].Y, vColor);
    end
    else
    begin
      FIntPoints.Add(Pointer(vPts[0].X));
      FIntPoints.Add(Pointer(vPts[0].Y));
      FIntPoints.Add(Pointer(vPts[1].X));
      FIntPoints.Add(Pointer(vPts[1].Y));
      Inc(vCnt);
    end;
  end;
  if vIsDrawOnBitMap then
    Windows.PolyPolyline(vDCMatrix, FIntPoints.List^, FCounts.List^,  vCnt);
  if vIsDrawOnCanvas then
    Windows.PolyPolyline(vDC, FIntPoints.List^, FCounts.List^, vCnt);
end;

procedure TsgDXFImage.DrawXRef(Sender: TObject);
begin
  AddSelectionMatrix(Sender);
  if TsgDXFImage(TsgDXFXref(Sender).CADImage) <> nil then
  begin
    FSHXFontsProc := TsgDXFImage(TsgDXFXref(Sender).CADImage).GetSHXFontsProc;
    FGetSelectionMatrixModeProc := TsgDXFImage(TsgDXFXref(Sender).CADImage).GetSelectionMatrixProc;
    FSetSelectionMatrixModeProc := TsgDXFImage(TsgDXFXref(Sender).CADImage).SetSelectionMatrixProc;
  end
  else
  begin
    FSHXFontsProc := GetSHXFontsProc;
    FGetSelectionMatrixModeProc := GetSelectionMatrixProc;
    FSetSelectionMatrixModeProc := SetSelectionMatrixProc;    
  end;
end;

procedure TsgDXFImage.TransformToUCS(var APoint: TFPoint);
var
  UCS: TFMatrix;

  function PtXMat(const P: TFPoint; const M: TFMatrix): TFPoint;
    function Part(I: Integer): Extended;
    begin
      Result := P.X * M[I,0] + P.Y * M[I,1] + P.Z * M[I,2] + M[3,I];
    end;
  begin
    Result.X := Part(0);
    Result.Y := Part(1);
    Result.Z := Part(2);
  end;

begin
  UCS := FConverter.GetUCS(FCurrentLayout);
  {APoint.X := APoint.X - UCS.X;
  APoint.Y := APoint.Y - UCS.Y;
  APoint.Z := APoint.Z - UCS.Z;}
  APoint := PtXMat(APoint, UCS);
end;

procedure TsgDXFImage.TransformToWorldCS(var APoint: TFPoint);
var
  UCS: TFMatrix;
begin
  UCS := FConverter.GetUCS(FCurrentLayout);
  {APoint.X := APoint.X + UCS.X;
  APoint.Y := APoint.Y + UCS.Y;
  APoint.Z := APoint.Z + UCS.Z;}
end;

function TsgDXFImage.InternalToCommonUnits(Pt: TFPoint): TFPoint;
begin
  Result := Pt;
end;

function TsgDXFImage.CommonToInternalUnits(Pt: TFPoint): TFPoint;
begin
  Result := Pt;
end;

function TsgDXFImage.Measurement: TsgMeasurement;
begin
  case Integer(Converter <> nil) shl 1 + Integer(FConverter.HeadVarStruct.Measurement) of
    2:  Result.DistanceUnits := duInch;
    3:  Result.DistanceUnits := duMM;
  else
    Result.DistanceUnits := duNone;
  end;
  Result.AngularUnits := auNone;
end;

procedure TsgDXFImage.SetVisibleArea(Data: TPoint);
begin
  FVisibleArea := Data;
  sgVisibleArea := Data;
end;

initialization
  CF_DXF := RegisterClipboardFormat('SoftGold DXF Image');
  TPicture.RegisterFileFormat('dxf', 'AutoCAD DXF', TsgDXFImage);
  TPicture.RegisterClipboardFormat(CF_DXF, TsgDXFImage);
  CreateAcadPal;
  InitGradFill;

finalization
  if Msimg32 <> 0 then FreeLibrary(Msimg32);
  TPicture.UnRegisterGraphicClass(TsgDXFImage);
  DeleteObject(AcadPal);

end.

