{ ************************************************************ }
{ Delphi VCL Extensions }
{ }
{ CAD Databse classes. CAD Entities, sections, objects. }
{ TsgDXFConerter is main class to store the drawing database }
{ }
{ Copyright (c) 2002-2014 SoftGold software company }
{ }
{ ************************************************************ }

unit DXFConv;
{$INCLUDE SGDXF.INC}
{$INCLUDE CADSoftTools.INC}
// {$DEFINE SG_USEDWGVERSION}
{$DEFINE EVG}
{$IFOPT D+}
{ .$DEFINE CONV_REFCOUNT }
{ .$DEFINE SG_CALC_INSTANCE_SIZES }
{$ENDIF}

interface

uses
  Windows, SysUtils, Classes, Math, ActiveX, MVFont, Properties, sgConsts,
  SGLines, SHX, sgFunction, ExtData, sgLists, sgComparer, sgXMLParser,
  sgMeshBuilderWrapper
{$IFDEF SG_USEGDIPLUS}
    , GDIPlus
{$ENDIF}
{$IFDEF SGDEL_XE2}
    , System.Types, System.UITypes
{$ENDIF}
{$IFDEF SGFPC}
    , JwaWinGDI
{$ENDIF}
    , Graphics;

type
  EsgDXFHatchError = class(Exception);
  EsgCADCommonError = class(Exception);
  EsgLimitMemoryUsesException = class(Exception);
  EsgLimitTimeUsesException = class(Exception);
  EsgIncorrectNameLayer = class(Exception);

  // {$HPPEMIT '__interface IsgListOfEntities;'}
  // {$HPPEMIT 'typedef System::DelphiInterface<IsgListOfEntities> _di_IsgListOfEntities;'}

  TsgDXFAcadTable = class;
  TsgDXFAcadTableStyle = class;
  TsgDXFAttdef = class;
  TsgDXFAttrib = class;
  TsgDXFBlock = class;
  TsgDXFBlockRecord = class;
  TsgDXFBlockRecords = class;
  TsgDXFDimensionStyle = class;
  TsgDXFConverter = class;
  TsgDXFDictionary = class;
  TsgDXFEntity = class;
  TsgDXFField = class;
  TsgDXFFieldList = class;
  TsgDXFGroup = class;
  TsgDXFInsert = class;
  TsgDXFImageEnt = class;
  TsgDXFLayer = class;
  TsgDXFLayout = class;
  TsgDXFLineType = class;
  TsgDXFMText = class;
  TsgDXFObjectEntity = class;
  TsgDXFOwneredItem = class;
  TsgDXFProxy = class;
  TsgDXFTable = class;
  TsgDXFText = class;
  TsgDXFSection = class;
  TsgDXFSortEntsTable = class;
  TsgDXFStyle = class;
  TsgDXFViewport = class;
  TsgDXFVport = class;
  TsgDXFXref = class;
  TsgDXFImageDef = class;
  TConvStatus = (stDefault, stLoading, stEditing, stClearing, stDestroying,
    stReading);
  TConvSection = (csTables, csBlocks, csEntities, csLTypes, csLayers, csStyles,
    csDimStyles, csBlockRecords, csVPorts, csMLineStyles, csImageDefs,
    csLayouts, csTableStyles, csObjects);
  TsgDXFEntityClass = class of TsgDXFEntity;
  TFPointProc = procedure(const P: TFPoint) of object;
  TsgCADEntityProc = function(Entity: TsgDXFEntity): Integer of object;
{$IFDEF SG_BTI}
  TsgExtendedBlockData = class;
{$ENDIF}
  TsgCADFindFont = procedure(const AEntity: TsgDXFEntity;
    const AConverter: TsgDXFConverter; const ABigFont: Boolean;
    const AFontName: string; var AFontNameNew: string);
  TsgCADLoadEntitiy = function(const Entity: TsgDXFEntity;
    const Converter: TsgDXFConverter): Boolean;
  TsgDXFTextPos = (csNone, csFraction, csIndexes, csDenominator, csWord,
    csHiWord, csLowWord, csDivision, csDivHi, csDivLow, csDivend);
  TsgDimTextPosVert = (pvCenter, pvAbove, pvOutSide, pvJIS);

  PsgCADIterate = ^TsgCADIterate;

  TsgCADIterate = record
    Matrix: TFMatrix;
    DrawMatrix: TFMatrix;
    Insert: TsgDXFInsert;
    ConvertMatrixCurrentIndertToWCS: TFMatrix;
    Color: TColor;
    XScale: Single;
    YScale: Single;
    Angle: Single;
    Additional: Integer;
    LType: TsgLines;
  end;

  PsgArc = ^TsgArc;

  TsgArc = record
    Rect: TFRect;
    Center, Point1, Point2: TFPoint;
    Ang1, Ang2, Rx, Ry: Double;
    Valid: Boolean;
  end;

  PsgParagraphParams = ^TsgParagraphParams;

  TsgParagraphParams = packed record
    IsFirstLine: Boolean;
    IsFirstText: Boolean;
    I: TsgFloat; // offset by first line
    L: TsgFloat; // offset by all text in paragraph
    T: Integer; // count tab
    Tabs: array [0 .. 15] of Single;
    TabsCount: Integer;
  end;

  PsgTextParse = ^TsgTextParse;

  TsgTextParse = packed record
    FontParams: TsgFontParams;
    HasLine: Boolean;
    Offset: TF2DPoint;
    ParagraphParams: TsgParagraphParams;
    TextPos: TsgDXFTextPos;
    IsEmpty: Boolean;
    TwiddleCount: LongWord;
  end;

  TsgConverterParams = record
    CheckHandles: Boolean;
    FileName: string;
  end;

  PsgPolyFaceVertexIndexes = ^TsgPolyFaceVertexIndexes;
  TsgPolyFaceVertexIndexes = array [1 .. 4] of Integer;

  { IsgListOfEntities = interface
    [cnstGUID_ListOfEntities]
    function AddEntity(const AEntity: TsgDXFEntity): Integer;
    procedure Clear(const ADoFree: Boolean = True);
    function DeleteEntity(const AIndex: Integer): TsgDXFEntity;
    function GetCount: Integer;
    function GetEntity(const AIndex: Integer): TsgDXFEntity;
    function IndexOfEntity(const AEntity: TsgDXFEntity): Integer;
    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity): Boolean;
    procedure SetEntity(const AIndex: Integer; const AEntity: TsgDXFEntity);
    procedure ExchangeEntity(AIndex1, AIndex2: Integer);
    function RemoveEntity(const AEntity: TsgDXFEntity): Boolean;
    property Count: Integer read GetCount;
    property Entities[const AIndex: Integer]: TsgDXFEntity read GetEntity write SetEntity; default;
    end; }

  TsgXDataProcs = class
  public
    constructor Create; virtual; abstract;
    function AddEntity(const AEntity: TsgDXFEntity): Integer; virtual; abstract;
    function LoadEntity(const AEntity: TsgDXFEntity): Boolean; virtual;
      abstract;
    procedure LinkEntity(const AEntity: TsgDXFEntity); virtual; abstract;
    procedure Initialize(const AConv: TsgDXFConverter); virtual; abstract;
    procedure Finalize; virtual; abstract;
    function Import(const AEntTypeNum: Integer; PXData: Pointer): TsgDXFEntity;
      virtual; abstract;
    function IsInternalCADImage(const AImg: Pointer): Boolean; virtual;
      abstract;
  end;

  TsgClassXDataProcs = class of TsgXDataProcs;

  TsgStackObject = class(TList)
  public
    procedure Clear; override;
    function Pop: TsgDXFEntity;
    procedure Push(const AObject: TsgDXFEntity);
  end;

  TsgLinkObjectDataType = (lodtName, lodtHandle, lodtIndex, lodtDimArrow);

  TsgLinkObjectData = record
    LinkType: TsgLinkObjectDataType;
    case TsgLinkObjectDataType of
      lodtName:
        (Name: PChar);
      lodtHandle:
        (Handle: UInt64);
      lodtIndex:
        (Index: Integer);
      lodtDimArrow:
        (ArrowType: TsgDimArrowType);
  end;

  TsgLinkObject = class
  private
    // FRefs: TsgList;
    FObject: TsgDXFEntity;
    procedure SetName(const AName: string);
    function GetName: string;
  protected
    FData: TsgLinkObjectData;
    // property Refs: TsgList read FRefs;
  public
    constructor Create; overload;
    constructor Create(const ALinkObjectData: TsgLinkObjectData); overload;
    constructor Create(const AArrowType: TsgDimArrowType); overload;
    constructor Create(const AName: string); overload;
    constructor Create(const AHandle: UInt64;
      const ALinkType: TsgLinkObjectDataType = lodtHandle); overload;
    destructor Destroy; override;
    function GetObject(AOwner: TsgDXFEntity): TsgDXFEntity;
    property LinkType: TsgLinkObjectDataType read FData.LinkType;
    property Name: string read GetName write SetName;
  end;

  TsgMapEntities = class
  private
    FConverter: TsgDXFConverter;
    FEntitiesWithGeneratedHandles: TsgList;

    FEntities: TsgList;
    FFindEntity: TsgDXFObjectEntity;
  protected
    function UseEntity(const AEntity: TsgDXFEntity): Boolean;
    procedure RegEntity(const AEntity: TsgDXFEntity);
    procedure UnRegEntity(const AEntity: TsgDXFEntity);
  public
    constructor Create(const AConverter: TsgDXFConverter);
    destructor Destroy; override;
    procedure ApplyAndFreeGeneratedList;
    procedure AddEntityToGeneratedList(const AEntity: TsgDXFEntity);
    procedure AddEntitiesToGeneratedList(const AEntities: TsgDXFEntity);
    procedure CreateGeneratedList;
    function RemoveEntityFromGeneratedList(const AEntity: TsgDXFEntity)
      : Boolean;
    function HasGeneratedList: Boolean;

    procedure ActivateRegister;
    procedure UnActivateRegister;
    function GetEntityByHandle(const AHandle: UInt64): TsgDXFEntity;
  end;

  // ??? TsgDXFConverter should be inherited from TsgDXFGroup but..
  // it has entities[] inside and they work not with sections.. what is why it is written here speciall  //

  TsgConverterExtented = class
  private
    FOwner: TsgDXFConverter;
    FHandleArray: TsgInt64List;
    FSelectedHandles: TsgInt64List;
  protected
    function GetIndexHandle(const AValue: string): Integer;
  public
    constructor Create(const AOwner: TsgDXFConverter);
    destructor Destroy; override;
    function RestoreHandle(const AExtendHandle: string): Int64;
    procedure SaveHandle(const AValue: string; const AEntity: TsgDXFEntity);
    property SelectedHandles: TsgInt64List read FSelectedHandles;
  end;

  TsgDXFConverter = class(TsgListObject)
  private
    FConvExtended: TsgConverterExtented;
    FActiveVPort: TsgDXFVport;
    FAddedDimensionsCount: Integer;
    FAddedTablesCount: Integer;
    FAfterRead: TNotifyEvent;
    FAllArcsAsCurves: Boolean;
    FAutoInsert: Boolean;
    FBlocksSection: TsgDXFSection;
    FBlockRecords: TsgDXFTable;
    FBeforeRead: TNotifyEvent;
    FCanvas: TCanvas;
    FCount: Integer;
    FContainerXref: TsgDXFXref;
    FDefaultLayoutIndex: Integer;
    FDimStyles: TsgDXFTable;
    FExtents: TFRect;
    FFieldList: TsgDXFFieldList;
    FFileName: string;
    FOnFindFont: TsgCADFindFont;
    FHeadEnd: PAnsiChar;
    FHeadVarStruct: TsgHeadVarStruct;
    FImportMode: TsgImportMode;
    FImageDefs: TsgDXFTable;
    FIsCrossoverMatrix: Boolean;
    FIsHaveActiveVPort: Boolean;
    FLayers: TsgDXFTable;
    FLayouts: TsgDXFTable;
    FLimit: PAnsiChar;
    FLTypes: TsgDXFTable;
    FMain: TsgDXFSection;
    FMaxEntities: Integer;
    FMStyles: TsgDXFTable;
    FOnCreate: TNotifyEvent;
    FOnLayoutAdd: TNotifyEvent;
    FOnLayoutRemove: TNotifyEvent;
    FOnLoad: TsgCADEntityProc;
    FOnRead: TNotifyEvent;
    FOwnerConverter: TsgDXFConverter;
    FParams: PsgCADIterate;
    FPos: PAnsiChar;
{$IFDEF CONV_REFCOUNT}
    FRefCount: Integer;
    FRefEnts: TsgList;
{$ENDIF}
    FRefs: Integer;
    FSHXFonts: TsgSHXFontList;
    FSortEntsTables: TsgDXFTable;
    FSource: TCustomMemoryStream;
    FStatus: TConvStatus;
    FStyles: TsgDXFTable;
    FTableStyles: TsgDXFTable;
    FTablesSection: TsgDXFSection;
    FHeaderSection: TsgDXFSection;
    FObjectsSection: TsgDXFSection;
    FEntitiesSection: TsgDXFSection;
    FTransform3D: TFMatrix;
    FViewPortRect: TFRect;
    FViewPortCut: Boolean;
    FViewTwistMatrix: TFMatrix;
    FUseSHXFonts: Boolean;
    FVPorts: TsgDXFTable;
    FXRefs: TList;
    FXRefSearchPaths: TsgStringList;
    FMaxHandle: UInt64;
    FOwnSource: Boolean;
    FMapEntities: TsgMapEntities;
    FTotalACISLoading: Cardinal;
    FMeshQuality: Double;
{$IFDEF SG_BTI}
    FXDataProcs: TsgXDataProcs;
{$ENDIF}
    FEntityDictionary: TsgCollection;
    function CheckUnicode: Boolean;
    function CheckEqualHandle(const AEntity: TsgDXFEntity;
      const AHandles: TsgInt64List; const ALog: TStrings = nil): Integer;
    function FEntities: TsgDXFBlock;
    function GetActiveVPort: TsgDXFVport;
    function GetAngle: Single;
    function GetBlock(Index: Integer): TsgDXFBlock;
    function GetCodePage: Integer;
    function GetCount(Index: TConvSection): Integer;
    function GetCircleZoomPercent: Integer;
    function GetDefaultLayoutIndex: Integer;
    function GetDimStyle(Index: Integer): TsgDXFDimensionStyle;
    function GetDisplayImageFrame: Boolean;
    function GetEntity(const AIndex: Integer): TsgDXFEntity;
    function GetExtents: TFRect;
    function GetFieldList: TsgDXFFieldList;
    function GetHeadVarAsFPt(AName: string): TFPoint;
    function GetHideWipeouts: Boolean;
    function GetImageDef(const Index: Integer): TsgDXFImageDef;
    function GetLayer(Index: Integer): TsgDXFLayer;
    function GetLayout(const AIndex: Integer): TsgDXFLayout;
    function GetLayoutsCount: Integer;
    function GetLType(Index: Integer): TsgDXFLineType;
    function GetMainConverter(AMatrix: PFMatrix): TsgDXFConverter; overload;
    function GetMainConverter: TsgDXFConverter; overload;
    // function GetPaperSpace: Boolean; {$IFDEF SGDEL_6}deprecated{$IFDEF SGDEL_2009}'This procedure is obsolete and will be deleted in the next version!'{$ENDIF};{$ENDIF}
    function GetPointDisplayMode: Integer;
    function GetSection(Index: TConvSection): TsgDXFGroup;
    function GetSHXFonts: TsgSHXFontList;
    function GetStyle(Index: Integer): TsgDXFStyle;
    function GetTable(Index: Integer): TsgDXFTable;
    function GetVPort: TFPoint;
    function GetVPortByIndex(const AIndex: Integer): TsgDXFVport;
    function GetIs3D: Boolean;
    function GetXRefSearchPath: string;
    function GetXRefSearchPaths: TStringList;
    function IterateEntitiesInBlocks(const AProc: TsgCADLoadEntitiy): Boolean;
    procedure InitXRefConverter(const AXRefConv: TsgDXFConverter;
      const AXRef: TsgDXFXref);
    function NewTable(const AType: TConvSection): TsgDXFTable;
    procedure DeleteModelLayout;
    procedure DeletePaperLayout;
    procedure HeadVarStructInit;
    procedure SetSection(Index: TConvSection; Value: TsgDXFGroup);
    procedure FreeSource;
    procedure SetActiveVPort(const AValue: TsgDXFVport);
    procedure SetAngle(const AAngle: Single);
    procedure SetCircleZoomPercent(const AVal: Integer);
    procedure SetDisplayImageFrame(const Value: Boolean);
    procedure SetHideWipeouts(const Value: Boolean);
    procedure SetNumberOfPartsInCircle(const ACount: Integer);
    procedure SetNumberOfPartsInSpline(const ACount: Integer);
    procedure SetSource(Value: TCustomMemoryStream);
    procedure SetOwnSource(Value: Boolean);
    procedure SetVPort(const APt: TFPoint);
    // procedure SetPaperSpace(const AValue: Boolean);{$IFDEF SGDEL_6}deprecated{$IFDEF SGDEL_2009}'This procedure is obsolete and will be deleted in the next version!'{$ENDIF};{$ENDIF}
    procedure SetPointDisplayMode(const Value: Integer);
    procedure SetStatus(const AValue: TConvStatus);
    procedure SetLTScale(const Value: Double);
    procedure SetXRefSearchPath(const Value: string);
    function GetPHeadVarStruct: PsgHeadVarStruct;
    function GetXDataProcs: TsgXDataProcs;
    function GetConvExtended: TsgConverterExtented;
  protected
    FNumberOfPartsInSpline: Integer;
    FNumberOfPartsInCircle: Integer;
{$IFDEF SG_BTI}
    FPreclean: Boolean;
{$ENDIF}
    function AddAttribsByBlock(const AIns: TsgDXFInsert;
      const ABlock: TsgDXFBlock): Boolean;
    procedure ApplyXRecodData;
    procedure CreateEntitiesWithGeneratedHandles;
    procedure CreateXDataProcs(AClass: TsgClassXDataProcs = nil);
    procedure DestroyXDataProcs;
    procedure ClearBegin; virtual;
    procedure ClearEnd; virtual;
    class function CompareEntities(const AEnt1, AEnt2: Pointer): Integer;
    procedure FreeEntitiesWithGeneratedHandles;
    procedure AddEntitiesWithGeneratedHandles(const AEntity: TsgDXFEntity);
    function RemoveFromEntitiesWithGeneratedHandles(const AEntity
      : TsgDXFEntity): Boolean;
    procedure AddACADLayout(ALayout: TsgDXFLayout);
    function AddLineType(const ALTypeName: string; const AUniform: Boolean;
      const ADashes: array of Double): TsgDXFEntity;
    function AddDrawingLayout(ACADImage: TObject; AName: string): TsgDXFLayout;
    function BlockRecordNameByHandle(const AHandle: UInt64): string;
    // function BlockRecordByName(const AName: string): TsgDXFBlockRecord;
    function BlockRecordByHandle(const AHandle: UInt64): TsgDXFBlockRecord;
    function CheckActiveVPort(const AbsHeight: Double): Boolean;
    function CheckHandle(var AHandle: UInt64): Boolean;
    // function CheckBlockByName(const ABlock: TsgDXFBlock; const AMaxHandle: UInt64): Integer;
    function CustomEntByName(const AName: string; const ASection: TConvSection)
      : TsgDXFEntity;
    function CheckEqualHandles(const ALog: TStrings = nil): Integer;

    function CreateDimStyles(const AppLanguage: TsgLangugeID;
      const ACreate: Boolean): TsgDXFDimensionStyle;
    function CreateTextStyles(const AppLanguage: TsgLangugeID;
      const ACreate: Boolean): TsgDXFStyle;

    function DoFindFont(const AEntity: TsgDXFEntity; const ABigFont: Boolean;
      const AFontName: string): string;
    procedure ClearBlocks;
    function GetDWGVersion(const S: AnsiString; var AVersion: TsgDWGVersion)
      : Integer; virtual;
    function GetModelLayout: TsgDXFLayout;
    function GetModelMatrix: TFMatrix;
    procedure GenerateDisplayAndModelViewPort(const ALayout: TsgDXFLayout;
      const AWidth, AHeight: Double; const AMode: Integer;
      const ABox: PFRect = nil);
    function GetHeaderSection: TsgDXFSection;
    procedure Initialize; virtual;
    property PHeadVarStruct: PsgHeadVarStruct read GetPHeadVarStruct;
    // procedure ResetBlockRecords;
    procedure ReLoadEntities(const AReloadCircular: Boolean);
    procedure ReplaceLayout(Index: Integer; ALayout: TsgDXFLayout);
    function ReInitBlockByEntities(const AInserts: TList): Boolean;
    procedure ResetHandles;
    procedure SetHandSeed(const AMaxHandle: UInt64);
    procedure SetHandle(E: TsgDXFEntity);
    procedure SetHandleGroup(E: TsgDXFEntity);
    procedure SetCodePage(ACodePage: Integer);
    procedure SetLoading(Value: Boolean; APos: PAnsiChar);
    property TotalACISLoading: Cardinal read FTotalACISLoading
    // see procedure TsgDXFACISEntity.MeshBrepBuilder
      write FTotalACISLoading;
    // sections notifications
    procedure MainNotify(Ptr: Pointer; Action: TListNotification);
    procedure ObjectsNotify(Ptr: Pointer; Action: TListNotification);
    procedure TablesNotify(Ptr: Pointer; Action: TListNotification);
    procedure LayoutsNotify(Ptr: Pointer; Action: TListNotification);
    procedure EntityListNotify(Ptr: Pointer; Action: TListNotification);

    class procedure SetLayerNameOfPassingInspection(const ALayer: TsgDXFLayer;
      const AName: string);

    // call for initialization reader classes (dxf/dwg)
    class procedure RegisterXRefGraphicClass(AExt: string;
      AGraphicClass: TGraphicClass);
    class procedure UnRegisterXRefGraphicClass(AGraphicClass: TGraphicClass);

    // xml functions
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    function FromXMLSubEntities(const ANode: TsgNodeSample;
      const AResult: IsgResultNode = nil): Integer; override;
    function GetLayerByNode(const ANode: TsgNodeSample): TsgDXFLayer;
    function GetLineTypeByNode(const ANode: TsgNodeSample): TsgDXFLineType;

    function RestoreHandle(const ANode: TsgNodeSample): Int64; overload;
    function RestoreHandle(const AExtendHandle: string): Int64; overload;
    procedure SaveHandle(const AValue: string; const AEntity: TsgDXFEntity);

    property OnLoad: TsgCADEntityProc read FOnLoad write FOnLoad;
    property VPorts[const AIndex: Integer]: TsgDXFVport read GetVPortByIndex;
    property Status: TConvStatus read FStatus write SetStatus;
    property XDataProcs: TsgXDataProcs read GetXDataProcs;
  public
    constructor Create; override;
    constructor CreateEx(const AParams: TsgConverterParams);
    constructor CreateFromFile(const AFileName: string);
    destructor Destroy; override;

    function ToXML(const AParrentNode: TsgNode;
      const AMode: TsgXMLModes = cnstDefaultXMLMode): TsgNode; override;
    function FromXML(const ANode: TsgNodeSample;
      const AResult: IsgResultNode = nil): Integer; override;

    function AddLayout(ALayout: TsgDXFLayout): Integer;
    procedure FillMainSection;
    function AddXRef(ACADFile: TObject; AName: string; APos, AScale: TFPoint;
      Rotation: Single; const ALayout: TsgDXFLayout = nil): TsgDXFInsert;
    function AddXRefEx(ACADFile: TObject; AName: string; APos, AScale: TFPoint;
      Rotation: Single; ALayout: TsgDXFLayout;
      const AddXrefLayers: Boolean = True): TsgDXFInsert;
    function BlockByName(const AName: string): TsgDXFBlock;
    procedure CleaningLayouts(ADeletePSpace: Boolean);
    procedure Clear;
    function Count: Integer;
    function DeleteBlock(ABlock: TsgDXFBlock; DoFree: Boolean): Boolean;
    function DeleteDimStyle(AStyle: TsgDXFDimensionStyle;
      DoFree: Boolean): Boolean;
    function DeleteLayout(ALayout: TsgDXFLayout): Boolean;
    procedure DoCreate(Sender: TObject); dynamic;
    procedure DoExtents;
    function ExtractFromTable(const ATable: TsgDXFGroup;
      const AEntity: TsgDXFEntity): TsgDXFEntity;
    function FindEntityByHandle(const AHandle: UInt64): TsgDXFEntity;
    function FindObjByHandle(const AHandle: UInt64): TsgDXFEntity;
    function FindObjByHandles(const AHandles: TsgInt64List;
      const AEntities: TList; const AGroup: TsgDXFEntity = nil)
      : Integer; overload;
    function FindObjByHandles(const AHandles: TList; const AEntities: TList;
      const AGroup: TsgDXFEntity = nil): Integer; overload;
    function GenerateModelViewPort(const ACenter: TFPoint;
      const AWidth, AHeight: Double; const ALoad: Boolean;
      const AFitModel: Boolean = False): TsgDXFViewport;
    // Generates a standard ViewPort for Paper_Space (i.e. - basic display ViewPort)
    function GenerateDisplayViewPort(const AWidth, AHeight: Double)
      : TsgDXFViewport;
    procedure GetLayerNames(S: TStrings; DoClear, IncludeUnused: Boolean);
    function GetLTScale: Double;
    function GetUCS(ALayout: TsgDXFLayout): TFMatrix;
    function GetTransform3d: TFMatrix;
    class function GetPropertyName: string; override;
    procedure GetSubEntities(const AList: TList);
    function GetReference(AClass: TsgObjectClass; AName: string): TsgListObject;
    function GetTextPolylines(const AText: TsgDXFText;
      const AList: TList): Integer;
    function IntToColor(Value: Integer): TColor;
    procedure InitializeSections;
    {$IFDEF SGDEL_6}deprecated{$IFDEF SGDEL_2009}'This procedure is obsolete and will be deleted in the next version. Please, use the following procedure - InitializeSectionsBegin!'{$ENDIF}; {$ENDIF}
    procedure InitializeSectionsBegin;
    procedure InitializeSectionsEnd;
    procedure Iterate(Proc, FinishProc: TsgCADEntityProc;
      var Params: TsgCADIterate);
    function LayerByName(const AName: string): TsgDXFLayer;
    function LayoutByName(AName: string): TsgDXFLayout;
    function LinesByName(const AName: string): TsgLines;
    procedure Load;
    procedure Loads(E: TsgDXFEntity);
    procedure LoadsGroup(E: TsgDXFEntity);
    procedure LoadsByClasses(const AEntityClasses: array of TsgDXFEntityClass);
    function LTypeByName(const AName: string): TsgDXFLineType;
    function NewNamedEntity(AOwner: TsgDXFEntity; AClass: TsgDXFEntityClass;
      const AName: string): TsgDXFEntity;
    function NewNamedTable(const AName: string; AClassType: TsgDXFEntityClass)
      : TsgDXFTable;
    function NewEntity(AOwner: TsgDXFEntity; AClass: TsgDXFEntityClass)
      : TsgDXFEntity;
    function Pos: Integer;
    procedure Reference;
    procedure Release;
    function RemoveEntity(AEntity: TsgDXFEntity; DoFree: Boolean): Boolean;
    procedure SetTransform3d(AMatrix: TFMatrix);
    procedure SortEntities;
    function SortEntitiesInZDepth: Boolean;
    procedure SortEntitiesByHandle(const ATable, ABlock: TsgDXFEntity);
    procedure StopLoading; virtual;
    procedure SetSourceStream(S: TStream);
    function DimensionStyleByName(const AName: string): TsgDXFDimensionStyle;
    function StyleByName(const AName: string): TsgDXFStyle;
    function StyleByPrimaryFont(const AName: string): TsgDXFStyle;
    function TableStyleByName(const AName: string): TsgDXFAcadTableStyle;
    function ViewTwistMatrix: TFMatrix;
    property AfterRead: TNotifyEvent read FAfterRead write FAfterRead;
    property AllArcsAsCurves: Boolean read FAllArcsAsCurves
      write FAllArcsAsCurves;
    property Angle: Single read GetAngle write SetAngle;
    property AutoInsert: Boolean read FAutoInsert write FAutoInsert;
    property ActiveVPort: TsgDXFVport read GetActiveVPort write SetActiveVPort;
    property BeforeRead: TNotifyEvent read FBeforeRead write FBeforeRead;
    property Blocks[Index: Integer]: TsgDXFBlock read GetBlock;
    property CircleZoomPercent: Integer read GetCircleZoomPercent
      write SetCircleZoomPercent;
    property CodePage: Integer read GetCodePage;
    property Counts[Index: TConvSection]: Integer read GetCount;
    property DefaultLayoutIndex: Integer read GetDefaultLayoutIndex
      write FDefaultLayoutIndex;
    property DimensionStyles[Index: Integer]: TsgDXFDimensionStyle
      read GetDimStyle;
    property DisplayImageFrame: Boolean read GetDisplayImageFrame
      write SetDisplayImageFrame;
    property FieldList: TsgDXFFieldList read GetFieldList;
    property FileName: string read FFileName write FFileName;
    property HeadVarStruct: TsgHeadVarStruct read FHeadVarStruct
      write FHeadVarStruct;
    property IsCrossoverMatrix: Boolean read FIsCrossoverMatrix
      write FIsCrossoverMatrix;
    property IsHaveActiveVPort: Boolean read FIsHaveActiveVPort
      write FIsHaveActiveVPort;
    property Entities[const AIndex: Integer]: TsgDXFEntity read GetEntity;
    property Extents: TFRect read GetExtents write FExtents;
    property OnFindFont: TsgCADFindFont read FOnFindFont write FOnFindFont;
    property HeadEnd: PAnsiChar read FHeadEnd write FHeadEnd;
    property HideWipeouts: Boolean read GetHideWipeouts write SetHideWipeouts;
    property ImportMode: TsgImportMode read FImportMode write FImportMode;
    property Is3D: Boolean read GetIs3D;
    property Layers[Index: Integer]: TsgDXFLayer read GetLayer;
    property Layouts[const AIndex: Integer]: TsgDXFLayout read GetLayout;
    property ImageDefs[const Index: Integer]: TsgDXFImageDef read GetImageDef;
    property LayoutsCount: Integer read GetLayoutsCount;
    property LTScale: Double read GetLTScale write SetLTScale;
    property LTypes[Index: Integer]: TsgDXFLineType read GetLType;
    property Main: TsgDXFSection read FMain;
    property MaxHandle: UInt64 read FMaxHandle write FMaxHandle;
    property MaxEntities: Integer read FMaxEntities write FMaxEntities;
    property MeshQuality: Double read FMeshQuality write FMeshQuality;
    property NumberOfPartsInSpline: Integer read FNumberOfPartsInSpline
      write SetNumberOfPartsInSpline;
    property NumberOfPartsInCircle: Integer read FNumberOfPartsInCircle
      write SetNumberOfPartsInCircle;
    property OnCreate: TNotifyEvent read FOnCreate write FOnCreate;
    property OnRead: TNotifyEvent read FOnRead write FOnRead;
    property OnLayoutAdd: TNotifyEvent read FOnLayoutAdd write FOnLayoutAdd;
    property OnLayoutRemove: TNotifyEvent read FOnLayoutRemove
      write FOnLayoutRemove;
    // property PaperSpace: Boolean read GetPaperSpace write SetPaperSpace;
    property Params: PsgCADIterate read FParams write FParams;
    property PointDisplayMode: Integer read GetPointDisplayMode
      write SetPointDisplayMode;
    property Sections[Index: TConvSection]: TsgDXFGroup read GetSection
      write SetSection;
    property SHXFonts: TsgSHXFontList read GetSHXFonts;
    property Source: TCustomMemoryStream read FSource write SetSource;
    property OwnSource: Boolean read FOwnSource write SetOwnSource;
    property Styles[Index: Integer]: TsgDXFStyle read GetStyle;
    property Tables[Index: Integer]: TsgDXFTable read GetTable;
    // property Transform3D: TFMatrix read FTransform3D write FTransform3D;
    property UseSHXFonts: Boolean read FUseSHXFonts write FUseSHXFonts;
    property ViewPortCut: Boolean read FViewPortCut;
    property VPort: TFPoint read GetVPort write SetVPort;
    property XRefs: TList read FXRefs;
    property XRefSearchPath: string read GetXRefSearchPath
      write SetXRefSearchPath;
    property XRefSearchPaths: TStringList read GetXRefSearchPaths;
    property ConvExtended: TsgConverterExtented read GetConvExtended;
    // for internal using
  end;

  TsgDXFEntity = class(TsgListObject { , IsgListOfEntities } )
{$IFDEF SG_CALC_INSTANCE_SIZES}
  private
    class var TotalAllocated: Integer;
{$ENDIF}
  protected
    function AddEntUseInsert(const AEntity: TsgDXFEntity): Integer;
    {$IFDEF SG_INLINE}inline; {$ENDIF}
    function AddItem(const AItem: TsgDXFEntity): Integer; virtual;
    function AddHandleItem(const AItem: TsgDXFEntity): Integer; virtual;
    function BeginExtData(const AData: TsgCADExtendedData): Boolean; virtual;
    function CanDraw: Boolean; virtual;
    function CanHaveHandle: Boolean; virtual;

    function DeleteItem(const AItem: TsgDXFEntity): Integer; virtual;
    function DeleteHandleItem(const AItem: TsgDXFEntity): Integer; virtual;
    procedure EndExtData(const AData: TsgCADExtendedData); virtual;
    function HasDimesionStyle(const AStyle: Pointer = Pointer($1)): Boolean;
    function HasTextStyle(const AStyle: Pointer = Pointer($1)): Boolean;
    function GetBox: TFRect; virtual;
    function GetColor: TColor;
    function GetColorCAD: TsgColorCAD; virtual;
    function GetComplex: Boolean; virtual;
    function GetConverter: TsgDXFConverter; virtual;
    function GetCount: Integer; virtual;
    function GetEntity(const AIndex: Integer): TsgDXFEntity; virtual;
    function GetEntType: TsgCADEntities; virtual;
    function GetEntTypeEx: Integer; virtual;
    function GetEntClassEx: TsgEntClass; virtual;
    function GetExtrusion: TFPoint; virtual;
    function GetDictionary: TsgDXFEntity; virtual;
    function GetDimStyleInternal: Pointer; virtual;
    function GetTextStyleInternal: Pointer; virtual;
    procedure GroupClear; virtual;
    // methods Group* only for Direct export using
    function GetNamedItem: TObject; virtual;
    function GroupCreate(AConverter: TsgDXFConverter = nil): Boolean; virtual;
    function GroupExists: Boolean; virtual;
    function GroupHasAddedEntities: Boolean; virtual;
    function GroupGet: TsgDXFGroup; virtual;
    function GetInternalFlags: Byte; virtual;
    function GetHandle: UInt64; virtual;
    function GetLines: TsgLines; virtual;
    function GetLayer: TsgDXFLayer; virtual;
    function GetLineCap: Word; virtual;
    function GetLineJoin: Word; virtual;
    function GetLineType: TsgDXFLineType; virtual;
    function GetLineTypeScale: Double; virtual;
    function GetLineWeight: Double; virtual;
    function GetLineWeightScaled: Boolean; virtual;
    function GetName: string; virtual;
    function GetOnDraw: TNotifyEvent; virtual;
    function GetOwner: TsgDXFEntity; virtual;
    function GetPaperSpace: Integer; virtual;
    function GetSrcEnd: PAnsiChar; {$IFDEF SG_USEDXFSRC}virtual; {$ENDIF}
    function GetSrcStart: PAnsiChar; {$IFDEF SG_USEDXFSRC}virtual; {$ENDIF}
    function GetFlags: Integer; virtual;
    function GetVisible: Boolean; virtual;
    function GetVisibility: Boolean; virtual;
    procedure ChangeHandle(AConverter: TsgDXFConverter); virtual;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); virtual;
    function IsInvoke(AConverter: TsgDXFConverter): Boolean; virtual;
    function HasLineWeight: Boolean; virtual;

    procedure ClearReferences; virtual;
    procedure FreeReferences; virtual;
    procedure Loaded(AConverter: TsgDXFConverter);
    procedure LoadedInternal(AConverter: TsgDXFConverter); virtual;
    procedure Link(AConverter: TsgDXFConverter); virtual;
    procedure ListNotify(Ptr: Pointer; Action: TListNotification); virtual;
    procedure RemoveReferenceNotification(const ARefObj: TsgDXFEntity); virtual;

    procedure SetColor__(const Value: TColor);
    procedure SetColorCAD(const Value: TsgColorCAD); virtual;
    procedure SetConverter(const AConverter: TsgDXFConverter); virtual;
    procedure SetDictionary(const AValue: TsgDXFEntity); virtual;
    procedure SetExtrusion(const Value: TFPoint); virtual;
    procedure SetEntity(const AIndex: Integer;
      const AEntity: TsgDXFEntity); virtual;
    procedure SetInternalFlags(const Value: Byte); virtual;
    procedure SetHandle(const Value: UInt64); virtual;
    procedure SetLayer(const Value: TsgDXFLayer); virtual;
    procedure SetLineCap(const Value: Word); virtual;
    procedure SetLineJoin(const Value: Word); virtual;
    procedure SetLineType(const AValue: TsgDXFLineType); virtual;
    procedure SetLineTypeScale(Value: Double); virtual;
    procedure SetLineWeight(Value: Double); virtual;
    procedure SetLineWeightScaled(Value: Boolean); virtual;
    procedure SetName(const AName: string); virtual;
    procedure SetOnDraw(const Value: TNotifyEvent); virtual;
    procedure SetOwner(const Value: TsgDXFEntity); virtual;
    procedure SetPaperSpace(const Value: Integer); virtual;
    procedure SetSrcEnd(const Value: PAnsiChar); {$IFDEF SG_USEDXFSRC}virtual;
    {$ENDIF}
    procedure SetSrcStart(const Value: PAnsiChar); {$IFDEF SG_USEDXFSRC}virtual;
    {$ENDIF}
    procedure SetFlags(const Value: Integer); virtual;
    procedure SetVisible(Value: Boolean); virtual;
    procedure SetVisibility(const Value: Boolean); virtual;
    procedure StyleChanged(Sender: TObject); dynamic;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    procedure ToXMLSubEntities(const AParrentNode: TsgNode;
      const AMode: TsgXMLModes = cnstDefaultXMLMode); virtual;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    function FromXMLSubEntities(const ANode: TsgNodeSample;
      const AResult: IsgResultNode = nil): Integer; override;
    procedure EntityLoaded; override;
    property Group: TsgDXFGroup read GroupGet;
    property LineCap: Word read GetLineCap write SetLineCap;
    property LineJoin: Word read GetLineJoin write SetLineJoin;
    property LineWeightScaled: Boolean read GetLineWeightScaled
      write SetLineWeightScaled;
    property InternalFlags: Byte read GetInternalFlags write SetInternalFlags;
  public
    constructor Create; override;
    destructor Destroy; override;
{$IFDEF SG_CALC_INSTANCE_SIZES}
    class function NewInstance: TObject; override;
{$ENDIF}
    procedure FreeInstance; override;
    procedure AssignEntity(Source: TsgDXFEntity); virtual;
    procedure Clone(const Source: TsgDXFEntity);

    // functions of IsgListOfEntities
    procedure Clear(const ADoFree: Boolean = True); virtual;
    function AddEntity(const AEntity: TsgDXFEntity): Integer; virtual;
    function DeleteEntity(const AIndex: Integer): TsgDXFEntity; virtual;
    procedure ExchangeEntity(AIndex1, AIndex2: Integer); virtual;
    function IndexOfEntity(const AEntity: TsgDXFEntity): Integer; virtual;
    function IndexOfHandle(const AHandle: UInt64): Integer;
    function IndexOfName(const AName: string): Integer; virtual;
    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; virtual;
    function RemoveEntity(const AEntity: TsgDXFEntity): Boolean;

    function FindEntByName(const AName: string): TsgDXFEntity; virtual;
    function FindEntByHandle(const AHandle: UInt64;
      const AIterateChildren: Boolean = False;
      const AIterateInsert: Boolean = False): TsgDXFEntity;

    procedure Draw; virtual;
    function EntName: string; virtual;

    function ToXML(const AParrentNode: TsgNode;
      const AMode: TsgXMLModes = cnstDefaultXMLMode): TsgNode; override;
    function GetExtData(const AData: TsgCADExtendedData): Boolean; virtual;
    function GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean; virtual;
    function GetThickness: Double; virtual;
    function IsInsert: Boolean; virtual;
    function IsOnePixelOptimisationValid: Boolean; virtual;
    procedure SetColor(Value: TColor);
    {$IFDEF SGDEL_6}deprecated{$IFDEF SGDEL_2009}'This procedure is obsolete and will be deleted in the next version. Please, use the following property - ColorCAD!'{$ENDIF}; {$ENDIF}
    procedure SetExtData(const AData: TsgCADExtendedData); virtual;
    procedure SetLType(Value: TsgDXFEntity);
    procedure SetLWeight(Value: Integer); virtual;
    property Box: TFRect read GetBox;
    property Complex: Boolean read GetComplex;
    property Converter: TsgDXFConverter read GetConverter;
    property Count: Integer read GetCount;
    property Color: TColor read GetColor write SetColor__;
    property ColorCAD: TsgColorCAD read GetColorCAD write SetColorCAD;
    property Dictionary: TsgDXFEntity read GetDictionary write SetDictionary;
    property Entities[const AIndex: Integer]: TsgDXFEntity
      read GetEntity; default;
    property EntType: TsgCADEntities read GetEntType;
    property EntClass: TsgEntClass read GetEntClassEx;
    property Flags: Integer read GetFlags write SetFlags;
    property Handle: UInt64 read GetHandle write SetHandle;
    property Lines: TsgLines read GetLines;
    property LineType: TsgDXFLineType read GetLineType write SetLineType;
    property LineTypeScale: Double read GetLineTypeScale write SetLineTypeScale;
    property LineWeight: Double read GetLineWeight write SetLineWeight;
    property Layer: TsgDXFLayer read GetLayer write SetLayer;
    property Name: string read GetName write SetName;
    property OnDraw: TNotifyEvent read GetOnDraw write SetOnDraw;
    property Owner: TsgDXFEntity read GetOwner;
    property PaperSpace: Integer read GetPaperSpace write SetPaperSpace;
    property SrcEnd: PAnsiChar read GetSrcEnd write SetSrcEnd;
    property SrcStart: PAnsiChar read GetSrcStart write SetSrcStart;
    property Visible: Boolean read GetVisible write SetVisible;
    property Visibility: Boolean read GetVisibility write SetVisibility;
  end;

  TsgDXFEntitySampleCustom = class(TsgDXFEntity)
  private
    FConverter: TsgDXFConverter;
    FOnAfterChange: TsgObjChangeProperties;
    FOnBeforeChange: TsgObjChangeProperties;
  protected
    procedure AfterChange(const AType: TsgPropertyType);
    procedure BeforeChange(const AType: TsgPropertyType);
    function GetActiveHeadVar: PsgHeadVarStruct;
    function GetConverter: TsgDXFConverter; override;
    procedure SetConverter(const AConverter: TsgDXFConverter); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property OnAfterChange: TsgObjChangeProperties read FOnAfterChange
      write FOnAfterChange;
    property OnBeforeChange: TsgObjChangeProperties read FOnBeforeChange
      write FOnBeforeChange;
  end;

  TsgDXFEntitySample = class(TsgDXFEntitySampleCustom)
  private
    FBackGroundImage: TsgDXFImageEnt;
    FTextRotation: Double;
    function GetDimArrowType(const ADimProps: TsgDimStyle;
      const ANameValue: TsgDimNameVal): TsgDimArrowType;
    procedure CheckArroyType(const AValue: TsgDimArrowType);
    procedure SetDimArrowType(var ADimProps: TsgDimStyle;
      const ANameValue: TsgDimNameVal; const AType: TsgDimArrowType);
  protected
    function GetArrowSize: Double;
    function GetBackGroundImage: TsgDXFImageEnt;
    function GetColorCAD: TsgColorCAD; override;
    function GetDimBlk1: Byte;
    function GetDimBlk2: Byte;
    function GetDimLrBlk: Byte;
    function GetDimForceText: Integer;
    function GetDimExtLineExt: TsgFloat;
    function GetDimExtLineOffset: TsgFloat;
    function GetDimLFac: Double;
    function GetDimPrecision: Integer;
    function GetDimScale: Double;
    function GetDimStyle: TsgDXFDimensionStyle;
    function GetDimTextAlign: Integer;
    function GetDimTextColor: TsgColorCAD;
    function GetDimTextHeight: TsgFloat;
    function GetDimTextOffset: Double;
    function GetDimTextPosVert: TsgDimTextPosVert;
    function GetFontHeight: TsgFloat;
    function GetFontName: string;
    function GetLayer: TsgDXFLayer; override;
    function GetFilletRadius: Double;
    function GetLineType: TsgDXFLineType; override;
    function GetLineTypeScale: Double; override;
    function GetLineWeight: Double; override;
    function GetPointDisplayMode: Integer;
    function GetPointDisplaySize: Double;
    function GetTextStyle: TsgDXFStyle;
    function GetTextRotation: TsgFloat;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure SetArrowSize(const Value: Double);
    procedure SetBackGroundImage(const Value: TsgDXFImageEnt);
    procedure SetDimBlk1(const Value: Byte);
    procedure SetDimBlk2(const Value: Byte);
    procedure SetDimLrBlk(const Value: Byte);
    procedure SetDimForceText(const Value: Integer);
    procedure SetDimExtLineExt(const Value: TsgFloat);
    procedure SetDimExtLineOffset(const Value: TsgFloat);
    procedure SetDimLFac(const Value: Double);
    procedure SetDimPrecision(const Value: Integer);
    procedure SetDimScale(const Value: Double);
    procedure SetDimStyle(const Value: TsgDXFDimensionStyle);
    procedure SetDimTextAlign(const Value: Integer);
    procedure SetDimTextColor(const Value: TsgColorCAD);
    procedure SetDimTextHeight(const Value: TsgFloat);
    procedure SetDimTextOffset(const Value: Double);
    procedure SetDimTextPosVert(const Value: TsgDimTextPosVert);
    procedure SetFilletRadius(const Value: Double);
    procedure SetFontHeight(const Value: TsgFloat);
    procedure SetLayer(const Value: TsgDXFLayer); override;
    procedure SetLineType(const AValue: TsgDXFLineType); override;
    procedure SetLineTypeScale(Value: Double); override;
    procedure SetLineWeight(Value: Double); override;
    procedure SetPointDisplayMode(const Value: Integer);
    procedure SetPointDisplaySize(const Value: Double);
    procedure SetColorCAD(const Value: TsgColorCAD); override;
    procedure SetTextStyle(const Value: TsgDXFStyle);
    procedure SetTextRotation(const AValue: TsgFloat);
    function UseTextStyleFixedHeight: Boolean;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property BackGroundImage: TsgDXFImageEnt read GetBackGroundImage
      write SetBackGroundImage;
    property ArrowSize: Double read GetArrowSize write SetArrowSize;
    property BevelSize: Double read GetFilletRadius write SetFilletRadius;
    property DimBlk1: Byte read GetDimBlk1 write SetDimBlk1;
    property DimBlk2: Byte read GetDimBlk2 write SetDimBlk2;
    property DimLrBlk: Byte read GetDimLrBlk write SetDimLrBlk;
    property DimStyle: TsgDXFDimensionStyle read GetDimStyle write SetDimStyle;
    property DimTextHeight: TsgFloat read GetDimTextHeight
      write SetDimTextHeight;
    property DimForceText: Integer read GetDimForceText write SetDimForceText;
    property DimExtLineExt: TsgFloat read GetDimExtLineExt
      write SetDimExtLineExt;
    property DimExtLineOffset: TsgFloat read GetDimExtLineOffset
      write SetDimExtLineOffset;
    property DimLFac: Double read GetDimLFac write SetDimLFac;
    property DimPrecision: Integer read GetDimPrecision write SetDimPrecision;
    property DimScale: Double read GetDimScale write SetDimScale;
    property DimTextAlign: Integer read GetDimTextAlign write SetDimTextAlign;
    property DimTextColor: TsgColorCAD read GetDimTextColor
      write SetDimTextColor;
    property DimTextOffset: Double read GetDimTextOffset write SetDimTextOffset;
    property DimTextPosVert: TsgDimTextPosVert read GetDimTextPosVert
      write SetDimTextPosVert;
    property FilletRadius: Double read GetFilletRadius write SetFilletRadius;
    property FontName: string read GetFontName;
    property FontHeight: TsgFloat read GetFontHeight write SetFontHeight;
    property LineType: TsgDXFLineType read GetLineType write SetLineType;
    property LineTypeScale: Double read GetLineTypeScale write SetLineTypeScale;
    property PointDisplayMode: Integer read GetPointDisplayMode
      write SetPointDisplayMode;
    property PointDisplaySize: Double read GetPointDisplaySize
      write SetPointDisplaySize;
    property TextStyle: TsgDXFStyle read GetTextStyle write SetTextStyle;
    property TextRotation: TsgFloat read GetTextRotation write SetTextRotation;
  end;

  TsgEvacuationDefault = class(TsgDXFEntitySampleCustom)
  private
    FPathEvacucationColor: TsgColorCAD;
    FPathEvacucationLineTypeScale: Double;
    FPathEvacucationWidth: Double;
  protected
    function GetPathEvacColor: TsgColorCAD;
    function GetPathEvacLayer: string;
    function GetPathEvacLineTypeScale: Double;
    function GetPathEvacWidth: Double;
    procedure SetPathEvacColor(const Value: TsgColorCAD);
    procedure SetPathEvacLineTypeScale(const Value: Double);
    procedure SetPathEvacWidth(const Value: Double);
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property PathEvacucationColor: TsgColorCAD read GetPathEvacColor
      write SetPathEvacColor;
    property PathEvacucationLayer: string read GetPathEvacLayer;
    property PathEvacucationLineTypeScale: Double read GetPathEvacLineTypeScale
      write SetPathEvacLineTypeScale;
    property PathEvacucationWidth: Double read GetPathEvacWidth
      write SetPathEvacWidth;
  end;

  TsgOwneredItem = class;

  TsgTableItem = class(TObject)
  private
    FItem: TsgDXFEntity;
    function IsValidItem: Boolean; {$IFDEF SG_INLINE} inline; {$ENDIF}
    procedure SetItem(const Value: TsgDXFEntity); virtual;
  protected
    function GetItemObject(const AValue: TsgDXFEntity): TsgOwneredItem; virtual;
  public
{$IFDEF SG_CALC_INSTANCE_SIZES}
    class function NewInstance: TObject; override;
    procedure FreeInstance; override;
{$ENDIF}
    property Item: TsgDXFEntity read FItem write SetItem;
  end;

  TsgOwneredItem = class(TObject)
  private
    FOwner: TsgDXFEntity;
    FRefCount: Integer;
    procedure SetOwner(const AOwner: TsgDXFEntity);
  protected
    function GetAncestor: TsgDXFEntity; virtual;
  public
    constructor Create(AAncestor: TsgDXFEntity); virtual;
{$IFDEF SG_CALC_INSTANCE_SIZES}
    class function NewInstance: TObject; override;
    procedure FreeInstance; override;
{$ENDIF}
    function ObjAddRef: Integer; {$IFDEF SG_INLINE} inline; {$ENDIF}
    function ObjRelease: Integer; {$IFDEF SG_INLINE} inline; {$ENDIF}
    property Owner: TsgDXFEntity read FOwner write SetOwner;
    property RefCount: Integer read FRefCount;
    property Ancestor: TsgDXFEntity read GetAncestor;
  end;

  TsgNamedItem = class(TsgOwneredItem)
  private
    FAncestor: TsgDXFEntity;
    FName: string;
    procedure SetName(const AName: string);
  protected
    function GetAncestor: TsgDXFEntity; override;
  public
    constructor Create(AAncestor: TsgDXFEntity); override;
    property Name: string read FName write SetName;
  end;

  TsgDXFOwneredItem = class(TsgDXFEntity)
  private
    FHandle: UInt64;
    FNamedItem: TsgNamedItem;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetConverter: TsgDXFConverter; override;
    function GetHandle: UInt64; override;
    function GetName: string; override;
    function GetNamedItem: TObject; override;
    function GetOwner: TsgDXFEntity; override;
    procedure SetHandle(const Value: UInt64); override;
    procedure SetName(const AName: string); override;
    procedure SetOwner(const AValue: TsgDXFEntity); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function EntName: string; override;
    function GetStrValue: string; override;
  end;

  TsgDXFObjectEntity = class(TsgDXFEntity)
  private
    FConverter: TsgDXFConverter;
    FGroup: TsgDXFGroup;
    FHandle: UInt64;
    FLayerItem: TsgTableItem;
    FInternalFlags: Byte;
    FFlag: Integer; // use AUTOCAD
    FPenStyle: Word; // by GDI
{$IFDEF SG_USEDXFSRC}
    FSrcEnd: PAnsiChar;
    FSrcStart: PAnsiChar;
{$ENDIF}
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function CanHaveHandle: Boolean; override;
    procedure GroupClear; override;
    function GroupCreate(AConverter: TsgDXFConverter = nil): Boolean; override;
    function GroupFill(AConverter: TsgDXFConverter = nil): Boolean; virtual;
    function GroupGet: TsgDXFGroup; override;
    function GetConverter: TsgDXFConverter; override;
    function GetHandle: UInt64; override;
    function GetInternalFlags: Byte; override;
    function GetFlags: Integer; override;
    function GetLayer: TsgDXFLayer; override;
    function GetLineCap: Word; override;
    function GetLineJoin: Word; override;
    function GetLineWeightScaled: Boolean; override;
    function GetVisibility: Boolean; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    procedure SetConverter(const AConverter: TsgDXFConverter); override;
    procedure SetInternalFlags(const Value: Byte); override;
    procedure SetFlags(const Value: Integer); override;
    procedure SetHandle(const Value: UInt64); override;
    procedure SetLayer(const Value: TsgDXFLayer); override;
    procedure SetLineCap(const Value: Word); override;
    procedure SetLineJoin(const Value: Word); override;
    procedure SetLineWeightScaled(Value: Boolean); override;
    procedure SetOwner(const Value: TsgDXFEntity); override;
    procedure SetVisibility(const Value: Boolean); override;
{$IFDEF SG_USEDXFSRC}
    function GetSrcEnd: PAnsiChar; override;
    function GetSrcStart: PAnsiChar; override;
    procedure SetSrcEnd(const Value: PAnsiChar); override;
    procedure SetSrcStart(const Value: PAnsiChar); override;
{$ENDIF}
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
  end;

  TsgDXFObjectEntityColor = class(TsgDXFObjectEntity)
  private
    FColor: TsgColorCAD;
  protected
    function GetColorCAD: TsgColorCAD; override;
    procedure SetColorCAD(const Value: TsgColorCAD); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
  end;

  TsgDXFSeqend = class(TsgDXFObjectEntity)
  protected
    function GetEntType: TsgCADEntities; override;
  end;

  TsgDXFPlotSettings = class(TsgDXFOwneredItem)
  private
    FData: TsgPlotSettingsData;
    function GetPlotData: PsgPlotSettingsData;
    function GetCustomPrintScaleKoef: Double;
    function GetPaperArea: TFRect;
    function GetCadMargins: TF2DRect;
    function GetCadOffset: TF2DPoint;
    function GetMagrinsArea: TFRect;
    function GetStartPoint: TF2DPoint;
    function GetPrintableArea: TFRect;
    function GetPlotFrameArea: TFRect;
    function GetCustomPrintScale: TsgPlotScale;
    procedure SetCustomPrintScale(const AValue: TsgPlotScale);
    function GetIsLandscapePaper: Boolean;
    function GetLandScape: Boolean;
    procedure SetLandScape(const AValue: Boolean);
  protected
    function GetName: string; override;
    procedure SetName(const AName: string); override;
    property PlotData: PsgPlotSettingsData read GetPlotData;
    property IsLandscapePaper: Boolean read GetIsLandscapePaper;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetRotatedMargin: TF2DRect;
    procedure ResetForDefaultValue(ADefaultValue: PsgPlotSettingsData = nil);
    function SetDefaultValueByExtents(const ABox: TFRect): Boolean;
    // Standart PlotSettings Property
    property CurrentStyleSheet: string read FData.CurrentStyleSheet
      write FData.CurrentStyleSheet;

    property DenominatorOfCustomPrintScale: Double
      read FData.DenominatorOfCustomPrintScale
      write FData.DenominatorOfCustomPrintScale;
    property FloatingPointScaleFactor: Double
      read FData.FloatingPointScaleFactor write FData.FloatingPointScaleFactor;
    property NumeratorOfCustomPrintScale: Double
      read FData.NumeratorOfCustomPrintScale
      write FData.NumeratorOfCustomPrintScale;
    property CustomPrintScale: TsgPlotScale read GetCustomPrintScale
      write SetCustomPrintScale;
    property PaperImageOrigin: TF2DPoint read FData.PaperImageOrigin
      write FData.PaperImageOrigin;
    property PageSetupName: string read FData.PageSetupName write SetName;
    property PaperSize: string read FData.PaperSize write FData.PaperSize;
    property PlotLayoutFlags: TsgPlotLayoutFlags read FData.PlotLayoutFlags
      write FData.PlotLayoutFlags;
    property PlotOrigin: TF2DPoint read FData.PlotOrigin write FData.PlotOrigin;
    property PlotPaperSize: TF2DPoint read FData.PlotPaperSize
      write FData.PlotPaperSize;
    property PlotPaperUnits: TsgPlotPaperUnits read FData.PlotPaperUnits
      write FData.PlotPaperUnits;
    property PlotRotation: TsgPlotRotation read FData.PlotRotation
      write FData.PlotRotation;
    property PlotType: TsgPlotType read FData.PlotType write FData.PlotType;
    property PlotViewName: string read FData.PlotViewName
      write FData.PlotViewName;
    property PlotWindowAreaMax: TF2DPoint read FData.PlotWindowAreaMax
      write FData.PlotWindowAreaMax;
    property PlotWindowAreaMin: TF2DPoint read FData.PlotWindowAreaMin
      write FData.PlotWindowAreaMin;
    property PrintOrConfigName: string read FData.PrintOrConfigName
      write FData.PrintOrConfigName;
    property ShadePlotCustomDPI: Integer read FData.ShadePlotCustomDPI
      write FData.ShadePlotCustomDPI;
    property ShadePlotMode: Integer read FData.ShadePlotMode
      write FData.ShadePlotMode;
    property ShadePlotResolutionLevel: Integer
      read FData.ShadePlotResolutionLevel write FData.ShadePlotResolutionLevel;
    property StandardScaleType: Byte read FData.StandardScaleType
      write FData.StandardScaleType;
    property UnprintableMargin: TF2DRect read FData.UnprintableMargin
      write FData.UnprintableMargin;
    // Get area property
    property PlotFrameArea: TFRect read GetPlotFrameArea;
    property PlotMarginsArea: TFRect read GetMagrinsArea;
    property PlotPaperArea: TFRect read GetPaperArea;
    property PlotPrintableArea: TFRect read GetPrintableArea;
    // Main export Area
    property LandScape: Boolean read GetLandScape write SetLandScape;
    // before set this prop Set paper size
    //
    property CustomPrintScaleKoef: Double read GetCustomPrintScaleKoef;
  end;

  TsgDXFPenEntity = class(TsgDXFObjectEntityColor)
  private
    FLineTypeScale: Double;
  protected
    function GetLineTypeScale: Double; override;
    procedure SetLineTypeScale(Value: Double); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    function IsOnePixelOptimisationValid: Boolean; override; // evg
  end;

  TsgDXFObjectEntityLineType = class(TsgDXFPenEntity)
  private
    FLineTypeItem: TsgTableItem;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetLines: TsgLines; override;
    function GetLineType: TsgDXFLineType; override;
    procedure SetLineType(const AValue: TsgDXFLineType); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
  end;

  TsgDXFPenTableItem = class(TsgDXFOwneredItem)
  private
    FFlags: Integer;
  protected
    function GetFlags: Integer; override;
    procedure SetFlags(const Value: Integer); override;
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
  end;

  TsgDXFCustomColor = class(TsgDXFPenTableItem)
  private
    FColor: TsgColorCAD;
  protected
    function GetColorCAD: TsgColorCAD; override;
    procedure SetColorCAD(const Value: TsgColorCAD); override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
  end;

  TsgDXFScale = class(TsgDXFOwneredItem)
  private
    FModelScale: Double;
    FDescription: string;
    FLayoutScale: Double;
    procedure SetDescription(const AValue: string);
    procedure SetLayoutScale(const AValue: Double);
    procedure SetModelScale(const AValue: Double);
  protected
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
  public
    constructor Create; override;
    property Description: string read FDescription write SetDescription;
    property LayoutScale: Double read FLayoutScale write SetLayoutScale;
    property ModelScale: Double read FModelScale write SetModelScale;
  end;

  TsgDXFObjectContextData = class(TsgDXFOwneredItem)
  private
    FScaleItem: TsgTableItem;
    procedure SetScale(const Value: TsgDXFScale);
    function GetScale: TsgDXFScale;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
  public
    constructor Create; override;
    property Scale: TsgDXFScale read GetScale write SetScale;
  end;

  TsgDXFLineType = class(TsgDXFPenTableItem)
  private
    FLines: TsgLines;
  protected
    function GetLines: TsgLines; override;
    procedure FreeReferences; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    procedure SetLineTypeScale(Value: Double); override;
    procedure SetName(const AName: string); override;
  public
    constructor Create; override;
    procedure AddComplexElement(const AComplexType: Byte;
      const ADash, ARotation, AScale, AXOffset, AYOffset: Double;
      AStyle: TsgDXFStyle; const AShapeNumber: Byte; const AText: string = '';
      AScaleFactor: Double = cnstLTScale);
    procedure AddDashElement(const ADash: Double;
      AScaleFactor: Double = cnstLTScale);
    procedure AssignEntity(Source: TsgDXFEntity); override;
  end;

  TsgDXFLayer = class(TsgDXFCustomColor)
  private
    FLineTypeItem: TsgTableItem;
    FLineWeight: Double;
    { TODO: can be union as one field }
    FIsPlotting: Boolean;
    FFrozenByViewPort: Boolean;
    FIsCheckName: Boolean;
    FVisible: Boolean;
    function GetUsed: Boolean;
  protected
    procedure FreeReferences; override;
    function GetContainerLayer: TsgDXFLayer;
    function GetLocked: Boolean;
    function GetVisible: Boolean; override;
    function GetFrozen: Boolean;
    function GetFrozenByNewViewPort: Boolean;
    function GetIsPlotting: Boolean;
    function GetLines: TsgLines; override;
    function GetLineType: TsgDXFLineType; override;
    function GetLineWeight: Double; override;
    function GetXrefLink: Boolean;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    procedure SetFrozen(AFrozen: Boolean);
    procedure SetFrozenByNewViewPort(const Value: Boolean);
    procedure SetLineType(const AValue: TsgDXFLineType); override;
    procedure SetLineWeight(Value: Double); override;
    procedure SetLocked(const Value: Boolean);
    procedure SetName(const AName: string); override;
    procedure SetNameDirect(const AName: string);
    procedure SetXrefLink(const Value: Boolean);
    procedure SetVisible(Value: Boolean); override;
    property ContainerLayer: TsgDXFLayer read GetContainerLayer;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property Frozen: Boolean read GetFrozen write SetFrozen;
    property IsFrozenByViewPort: Boolean read FFrozenByViewPort
      write FFrozenByViewPort;
    property IsFrozenByNewViewPort: Boolean read GetFrozenByNewViewPort
      write SetFrozenByNewViewPort;
    property Locked: Boolean read GetLocked write SetLocked;
    property XrefLink: Boolean read GetXrefLink write SetXrefLink;
    property IsPlotting: Boolean read GetIsPlotting write FIsPlotting;
    property IsCheckName: Boolean read FIsCheckName write FIsCheckName;
    property Used: Boolean read GetUsed;
  end;

  TsgDXFBlockRecord = class(TsgDXFObjectEntity)
  private
    FBlock: TsgDXFBlock;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetName: string; override;
    procedure SetName(const AName: string); override;
    property Block: TsgDXFBlock read FBlock write FBlock;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    function EntName: string; override;
    function AddEntity(const AEntity: TsgDXFEntity): Integer; override;
    function DeleteEntity(const AIndex: Integer): TsgDXFEntity; override;
    procedure ExchangeEntity(AIndex1, AIndex2: Integer); override;
    function IndexOfEntity(const AEntity: TsgDXFEntity): Integer; override;
    // function IndexOfHandle(const AHandle: UInt64): Integer;
    function IndexOfName(const AName: string): Integer; override;
    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; override;
  end;

  TsgDXFGroup = class(TsgDXFObjectEntity)
  private
    // FSortHandles: TsgCollection;
    FBox: TFRect;
    FEntities: TListNotify;
  protected
    FViewPortOrdIndex: Integer;
    FViewPortWithMinIndex: TsgDXFViewport;
    procedure AddEntities(const ASource: TsgDXFEntity;
      AConverter: TsgDXFConverter = nil);
    // function AddHandleItem(const AItem: TsgDXFEntity): Integer; override;
    // function DeleteHandleItem(const AItem: TsgDXFEntity): Integer; override;
    procedure SetViewPortProperty(const AViewPort: TsgDXFViewport;
      const APaperSpaceBlock: Boolean);
    procedure FreeReferences; override;
    function GetBox: TFRect; override;
    function GetCount: Integer; override;
    function GetEntity(const AIndex: Integer): TsgDXFEntity; override;
    procedure ApplyBox; virtual;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure SetEntity(const AIndex: Integer;
      const AEntity: TsgDXFEntity); override;
    procedure SortEntByHandle;
  public
    constructor Create; override;
    procedure Iterate(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); virtual;
    function GetStrValue: string; override;
    // functions of IsgListOfEntities
    function DeleteEntity(const AIndex: Integer): TsgDXFEntity; override;
    procedure ExchangeEntity(AIndex1, AIndex2: Integer); override;
    procedure Clear(const ADoFree: Boolean = True); override;
    function IndexOfEntity(const AEntity: TsgDXFEntity): Integer; override;
    function IndexOfName(const AName: string): Integer; override;
    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; override;
{$IFDEF SGDEL_2005}
    function GetEnumerator: TListEnumerator;
{$ENDIF}
  end;

  TsgDXFGroupName = class(TsgDXFGroup)
  private
    FOnListNotify: TsgObjProcListNotify;
    FNamedItem: TsgNamedItem;
    function GetOnListNotify: TsgObjProcListNotify;
    procedure SetOnListNotify(const Value: TsgObjProcListNotify);
  protected
    procedure FreeReferences; override;
    procedure DoListNotify(Ptr: Pointer; Action: TListNotification); dynamic;
    function GetName: string; override;
    function GetNamedItem: TObject; override;
    function GetOwner: TsgDXFEntity; override;
    procedure ListNotify(Ptr: Pointer; Action: TListNotification); override;
    procedure SetName(const AName: string); override;
    procedure SetOwner(const Value: TsgDXFEntity); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property OnListNotify: TsgObjProcListNotify read GetOnListNotify
      write SetOnListNotify;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function EntName: string; override;
  end;

  TsgDXFCustomVertex = class(TsgDXFObjectEntityLineType)
  private
    FPoint: TFPoint;
  protected
    function CanDraw: Boolean; override;
    function GetBox: TFRect; override;
    function GetPoint: TFPoint; virtual;
    procedure SetPoint(AValue: TFPoint); virtual;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property Point: TFPoint read GetPoint write SetPoint;
  end;

  TsgDXFVertex = class(TsgDXFEntity)
  private
    FFlags: Integer;
    FHandle: UInt64;
    FPoint: TFPoint;
    function GetPolyFaceIndex1: Integer;
    function GetPolyFaceIndex2: Integer;
    function GetPolyFaceIndex3: Integer;
    function GetPolyFaceIndex4: Integer;
    procedure NewPolyFaceIndexes;
    procedure SetPolyFaceIndex1(const Value: Integer);
    procedure SetPolyFaceIndex2(const Value: Integer);
    procedure SetPolyFaceIndex3(const Value: Integer);
    procedure SetPolyFaceIndex4(const Value: Integer);
    function GetPolyFaceIndex(Index: Integer): Integer;
    procedure SetPolyFaceIndex(Index: Integer; const Value: Integer);
  protected
    FBulge: Double;
    FEndWidth: Double;
    FPolyFaceIndexes: PsgPolyFaceVertexIndexes;
    FStartWidth: Double;
    function CanHaveHandle: Boolean; override;
    procedure FreeReferences; override;
    function GetBox: TFRect; override;
    function GetInternalFlags: Byte; override;
    function GetHandle: UInt64; override;
    function GetPoint: TFPoint;
    function GetFlags: Integer; override;
    function GetIs3DVertex: Boolean;
    function GetBulge: Double;
    function GetEndWidth: Double;
    function GetStartWidth: Double;
    procedure SetHandle(const AValue: UInt64); override;
    procedure SetPoint(const AValue: TFPoint);
    procedure SetFlags(const Value: Integer); override;
    procedure SetIs3DVertex(const Value: Boolean);
    procedure SetBulge(const Value: Double);
    procedure SetEndWidth(const Value: Double);
    procedure SetStartWidth(const Value: Double);
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function IsSplineFrameControlPoint: Boolean;
    function IsPolyfaceMeshVertex: Boolean;
    function HasBulge: Boolean;
    property Bulge: Double read GetBulge write SetBulge;
    property EndWidth: Double read GetEndWidth write SetEndWidth;
    property Is3DVertex: Boolean read GetIs3DVertex write SetIs3DVertex;
    property Point: TFPoint read FPoint write FPoint;
    property PolyFaceVertexIndex1: Integer read GetPolyFaceIndex1
      write SetPolyFaceIndex1;
    property PolyFaceVertexIndex2: Integer read GetPolyFaceIndex2
      write SetPolyFaceIndex2;
    property PolyFaceVertexIndex3: Integer read GetPolyFaceIndex3
      write SetPolyFaceIndex3;
    property PolyFaceVertexIndex4: Integer read GetPolyFaceIndex4
      write SetPolyFaceIndex4;
    property PolyFaceVertexIndex[Index: Integer]: Integer read GetPolyFaceIndex
      write SetPolyFaceIndex;
    property StartWidth: Double read GetStartWidth write SetStartWidth;
  end;

  TsgDXFPenLine = class(TsgDXFCustomVertex)
  private
    FExtrusion: PFPoint;
    FLineWeight: Double;
    FZThick: Double;
  protected
    procedure AddThickness(var R: TFRect);
    procedure ApplyExtrusionByPoint; virtual;
    procedure FreeReferences; override;
    function IsExtruded: Boolean; virtual;
    function GetBox: TFRect; override;
    function GetExtrusion: TFPoint; override;
    function GetLineWeight: Double; override;
    function GetZThick: Double;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure SetExtrusion(const Value: TFPoint); override;
    procedure SetLineWeight(Value: Double); override;
    procedure SetZThick(const Value: Double);
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetThickness: Double; override;
    property Extrusion: TFPoint read GetExtrusion write SetExtrusion;
    procedure SetLWeight(Value: Integer); override;
    property ZThick: Double read GetZThick write SetZThick;
  end;

  TsgDXFLine = class(TsgDXFPenLine)
  private
{$IFNDEF EVG} FDottedSingPts: TList; {$ENDIF}
    FPoint1: TFPoint;
  protected
    procedure ApplyExtrusionByPoint; override;
    function GetAngle: TsgFloat;
    function GetBox: TFRect; override;
    function GetEntType: TsgCADEntities; override;
    function GetLength: TsgFloat;
    function GetPoint1: TFPoint;
    procedure AddZThick(var R: TFRect);
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure SetAngle(const Value: TsgFloat);
    procedure SetPoint1(AValue: TFPoint);
    procedure SetLength(const Value: TsgFloat);
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property Angle: TsgFloat read GetAngle write SetAngle;
{$IFNDEF EVG} property DottedSingPts: TList read FDottedSingPts;
    {$ENDIF}
    function GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean; override;
    property Point1: TFPoint read FPoint1 write FPoint1;
    property Length: TsgFloat read GetLength write SetLength;
  end;

  TsgDXFPoint = class(TsgDXFPenLine)
  private
    FPoints: TList;
  protected
    procedure ApplyExtrusionByPoint; override;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    procedure ClearPoints;
    function GetBox: TFRect; override;
    function GetEntType: TsgCADEntities; override;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    property Points: TList read FPoints;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean; override;
  end;

  // InternalFlags: Integer;
  //
  // $40 - n(Point, Point1, Point2) = 0;
  // $10 - n(Point, Point1, Point2) - dir to front
  //
  // $80 - n(Point, Point2, Point3) = 0;
  // $20 - n(Point, Point2, Point3) - dir to front

  TsgDXFSolid = class(TsgDXFLine)
  private
    FPoint2: TFPoint;
    FPoint3: TFPoint;
    FMatrix: PFMatrix;
  protected
    procedure CalcState; virtual;
    procedure FreeReferences; override;
    function GetEntType: TsgCADEntities; override;
    function GetBox: TFRect; override;
    function GetMatrix: TFMatrix; virtual;
    function GetPoint2: TFPoint;
    function GetPoint3: TFPoint;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure SetExtrusion(const Value: TFPoint); override;
    procedure SetPoint2(AValue: TFPoint);
    procedure SetPoint3(AValue: TFPoint);
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean; override;
    function GetPoints(var APoints4: TsgPoints4;
      const AAddZThick: Boolean = False;
      const AExtruding: Boolean = False): Integer;
    property Point2: TFPoint read GetPoint2 write SetPoint2;
    property Point3: TFPoint read GetPoint3 write SetPoint3;
  end;

  TsgDXFSortEntsTable = class(TsgDXFOwneredItem)
  private
    FObject: TsgDXFEntity;
    FHandlesNew: TsgInt64List;
    FHandlesOld: TsgInt64List;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    procedure FindMinMaxHandles(const AEntities: TList;
      var AHandleMin, AHandleMax: UInt64);
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    procedure ReplaceHandles(const AEntities: TList;
      const ACurrent, ANew: TsgInt64List);
    procedure SortEntitiesList(const AEntities: TList);
    procedure SortSmallList(const AEntities: TList;
      const AHandleMin, AHandleMax: UInt64);
    procedure SortByQwickMetod(const AEntities: TList);
  public
    constructor Create; override;
    function SortEntities(const AGroup: TsgDXFEntity): Boolean;
    function ReplaceHandle(AEntity: TsgDXFEntity): Boolean;
    property HandlesNew: TsgInt64List read FHandlesNew;
    property HandlesOld: TsgInt64List read FHandlesOld;
    property SortObject: TsgDXFEntity read FObject write FObject;
  end;

  TsgDXFTrace = class(TsgDXFSolid)
    function GetEntType: TsgCADEntities; override;
  end;

  TsgDXF3dFace = class(TsgDXFSolid)
  private
    FFlags: Integer;
  protected
    function GetEntType: TsgCADEntities; override;
    function GetFlags: Integer; override;
    procedure SetFlags(const Value: Integer); override;
  public
  end;

  TsgSTL3dFace = class(TsgDXF3dFace)
  protected
    procedure CalcState; override;
  end;

  TsgCADBasePolyline = class(TsgDXFPenLine)
  private
    FPolyPoints: TFPointList;
{$IFNDEF EVG} FDottedSingPts: TList; {$ENDIF}
    FFlags: Integer;
    FBox: TFRect;
    procedure DoExtrusions;
    function GetPolyPoint(Index: Integer): TFPoint;
{$IFNDEF EVG} function GetDottedPoint(Index: Integer): TFPoint; {$ENDIF}
    function GetIsPolyZThickness: Boolean;
  protected
    procedure AddZTicks(AList: TFPointList);
    procedure DoZThickAndElevation; virtual;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    procedure DoZThickness(const APointsCounts: TsgIntegerList);
    function GetBox: TFRect; override;
    function GetClosed: Boolean; virtual;
    function GetElevation: Double; virtual;
    function GetIsMeshMClosed: Boolean;
    function GetIsMeshNClosed: Boolean;
    function GetIsPolygonMesh: Boolean; virtual;
    function GetIsPLinegen: Boolean;
    function GetFlags: Integer; override;
    function GetPolySign: Integer;
    procedure SetClosed(const AClosed: Boolean); virtual;
    procedure SetPLineGen(const APLineGen: Boolean); virtual;
    procedure SetFlags(const Value: Integer); override;
    procedure SetPolySign(const AValue: Integer);
    procedure ApplyBox; virtual;
{$IFNDEF EVG} procedure CreateDottedList; virtual; {$ENDIF}
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure ReloadPolyPoints; virtual;
    function IsPathEvacuation: Boolean;
    function IsPolyPointsSolid: Boolean;
    function GetArea: Double; virtual;
    function GetLength: Double; virtual;
    property IsMeshMClosed: Boolean read GetIsMeshMClosed;
    property IsMeshNClosed: Boolean read GetIsMeshNClosed;
    property IsPolygonMesh: Boolean read GetIsPolygonMesh;
    property PolySign: Integer read GetPolySign write SetPolySign;
  public
    constructor Create; override;
    function GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean; override;
{$IFNDEF EVG} function DottedCount: Integer; {$ENDIF}
    function PointCount: Integer;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function HasWidth(const AFull: Boolean = True): Boolean; virtual;
    property Closed: Boolean read GetClosed write SetClosed;
{$IFNDEF EVG} property DottedSingPts: TList read FDottedSingPts; {$ENDIF}
{$IFNDEF EVG} property DottedPoints[Index: Integer]: TFPoint read GetDottedPoint; {$ENDIF}
    property IsPLinegen: Boolean read GetIsPLinegen write SetPLineGen;
    property IsPolyZThickness: Boolean read GetIsPolyZThickness;
    property PolyPoints: TFPointList read FPolyPoints;
    property Points[Index: Integer]: TFPoint read GetPolyPoint; default;
  end;

  TsgDXFPolyline = class(TsgCADBasePolyline)
  private
    FArrows: TFPointList;
    FArrowsLines: TsgLines;
    FEntities: TListNotify;
    FMeshM: Integer;
    FMeshN: Integer;
    FPolyFaceVertexIndexes: TList;
    FPolyLineEntities: TList;
    FStartW: Double;
    FEndW: Double;
    FGlobalW: Double;
    FPointsCounts: TsgIntegerList; // evg
    procedure ApplyBulgeByPoint(P1, P2: TFPoint; Bulge: Double;
      AList: TFPointList; ANumberOfCircleParts: Integer);
    procedure DoVertexes;
    function GetBulgeHeight(const AIndex: Integer): Double;
    function GetEntities: TList;
    function GetIsPolyFaceMesh: Boolean;
    function GetVertex(Index: Integer): TsgDXFVertex;
    procedure SetBulgeHeight(const AIndex: Integer; const AHeight: Double);
    procedure SetPointsCounts(const Value: TsgIntegerList);
    procedure SetPolyline3D(const Value: Boolean);
  protected
    procedure DoZThickAndElevation; override;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    procedure DoArrows(const ALines: TsgLines; const AMatrix: PFMatrix);
    function GetCount: Integer; override;
    function GetEntity(const AIndex: Integer): TsgDXFEntity; override;
    function GetEntType: TsgCADEntities; override;
    function GetElevation: Double; override;
    function GetGlobalWidth: Double;
    function GetIsPolygonMesh: Boolean; override;
    procedure GetVertexListForPolygonMesh(MeshM, MeshN: Integer;
      AVertexList: TFPointList; AVertexIndexList: TsgIntegerList);
    procedure GetVertexListForPolyFaceMesh(AVertexList: TFPointList);
    function IsExtruded: Boolean; override;
    function Is3dPolyline: Boolean;
    function Is3dPolygonMesh: Boolean;
    procedure SetEntity(const AIndex: Integer;
      const AEntity: TsgDXFEntity); override;
    procedure SetElevation(const AValue: Double);
    procedure SetGlobalWidth(AValue: Double);
    procedure ApplyBox; override;
    procedure ReloadPolyPoints; override;
    function GetArea: Double; override;
    function GetLength: Double; override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property ArrowsLines: TsgLines read FArrowsLines;
    property BulgeHeight[const AIndex: Integer]: Double read GetBulgeHeight
      write SetBulgeHeight;
    property List: TListNotify read FEntities;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;

    // functions of IsgListOfEntities
    function DeleteEntity(const AIndex: Integer): TsgDXFEntity; override;
    procedure Clear(const ADoFree: Boolean = True); override;
    function IndexOfEntity(const AEntity: TsgDXFEntity): Integer; override;
    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; override;

    procedure Iterate(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); virtual;
    function HasWidth(const AFull: Boolean = True): Boolean; override;
    property Arrows: TFPointList read FArrows write FArrows;
    property EndWidth: Double read FEndW write FEndW;
    property Elevation: Double read GetElevation write SetElevation;
    property GlobalWidth: Double read FGlobalW write FGlobalW;
    property Polyline3D: Boolean read Is3dPolyline write SetPolyline3D;
    property IsMeshMClosed;
    property IsMeshNClosed;
    property IsPolyFaceMesh: Boolean read GetIsPolyFaceMesh;
    property IsPolygonMesh;
    property MeshM: Integer read FMeshM write FMeshM;
    property MeshN: Integer read FMeshN write FMeshN;
    property PolyFaceVertexIndexes: TList read FPolyFaceVertexIndexes;
    property PolyLineEntities: TList read FPolyLineEntities;
    property StartWidth: Double read FStartW write FStartW;
    property PointsCounts: TsgIntegerList read FPointsCounts
      write SetPointsCounts; // evg
    property Vertexes[Index: Integer]: TsgDXFVertex read GetVertex;
  end;

  TsgDXFLWPolyline = class(TsgDXFPolyline)
    // evg//  TsgDXFLWPolyline = class(TsgDXFBasePolyline)
  protected
    function GetEntType: TsgCADEntities; override;
    function HasLineWeight: Boolean; override;
  end;

  TsgDWGPolyline = class(TsgDXFPolyline)
  public
    constructor Create; override;
    {$IFDEF SGDEL_6}deprecated{$IFDEF SGDEL_2009}'This class will be deleted in the next version. Please, use the following class - TsgDXFPolyline!'{$ENDIF}; {$ENDIF}
  end;

  TsgDXFSplineProc = procedure(const P: TFPoint) of object;

  TsgDXFSpline = class(TsgCADBasePolyline)
  private
    FBeginningTangent: TFPoint;
    FControls: TFPointList;
    FDegree: Byte;
    FEndingTangent: TFPoint;
    FFit: TFPointList;
    FKnots: TsgSingleList;
    FLen: Double;
    FWeights: TsgSingleList;
    FFlagsExtented: Integer;
    function GetIsByAngles: Boolean;
    function GetControlPoint(Index: Integer): TFPoint;
    function GetFitPoint(Index: Integer): TFPoint;
    function GetKnot(const AIndex: Integer): Single;
    procedure SetKnot(const AIndex: Integer; const Value: Single);
    function GetWeight(const AIndex: Integer): Single;
    procedure SetWeight(const AIndex: Integer; const Value: Single);
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    procedure AddKnot(const X: Extended);
    function GetBeginningTangent: TFPoint;
    function GetEndingTangent: TFPoint;
    function GetEntType: TsgCADEntities; override;
    function GetDegree: Byte;
    // extented data
    function BeginExtData(const AData: TsgCADExtendedData): Boolean; override;
    procedure EndExtData(const AData: TsgCADExtendedData); override;

    procedure SetBeginningTangent(AValue: TFPoint);
    procedure SetEndingTangent(AValue: TFPoint);
    procedure SetDegree(const Value: Byte);
    procedure BuildSplineAsPoly;
    procedure BuildSplineByAngles(const ANumberOfParts: Integer);
{$IFNDEF EVG} procedure CreateDottedList; override; {$ENDIF}
    procedure GetSpline(const ANumberOfParts: Integer);
    function IsRational: Boolean;
    function IsPolyline: Boolean; virtual;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure ReloadPolyPoints; override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property FlagsExtented: Integer read FFlagsExtented write FFlagsExtented;
  public
    constructor Create; override;
    procedure AddWeight(const W: Extended);
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function ControlCount: Integer;
    function FitCount: Integer;
    function GetExtData(const AData: TsgCADExtendedData): Boolean; override;
    function KnotCount: Integer;
    function WeightCount: Integer;
    procedure GetPoints(Proc: TsgDXFSplineProc; XScale, YScale: Extended);
    property BeginningTangent: TFPoint read FBeginningTangent
      write FBeginningTangent;
    property ControlPoints[Index: Integer]: TFPoint read GetControlPoint;
    property Controls: TFPointList read FControls { write FControls };
    property Degree: Byte read GetDegree write SetDegree;
    property EndingTangent: TFPoint read FEndingTangent write FEndingTangent;
    property FitPoints[Index: Integer]: TFPoint read GetFitPoint;
    property Fit: TFPointList read FFit;
    property IsByAngles: Boolean read GetIsByAngles;
    property Knot[const AIndex: Integer]: Single read GetKnot write SetKnot;
    property Knots: TsgSingleList read FKnots;
    property Length: Double read FLen;
    property Weight[const AIndex: Integer]: Single read GetWeight
      write SetWeight;
  end;

  TsgDXFCircle = class(TsgCADBasePolyline)
  private
    FRadius: TsgFloat;
  protected
    function GetEntType: TsgCADEntities; override;
    function GetRadius: TsgFloat;
    function GetClosed: Boolean; override;
    procedure SetClosed(const AClosed: Boolean); override;
    procedure SetRadius(AValue: TsgFloat);
{$IFNDEF EVG} procedure CreateDottedList; override; {$ENDIF}
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Params(var A, B, AStart, AEnd, ASin, ACos: Double); virtual;
    procedure ReloadPolyPoints; override;
    function CircleParamsToXMLNode(const ANode: TsgNode;
      const AMode: TsgXMLModes = []): Integer; virtual;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    function GetArea: Double; override;
    function GetLength: Double; override;
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property Radius: TsgFloat read GetRadius write SetRadius;
    property Area: Double read GetArea;
    property Length: Double read GetLength;
  end;

  TsgDXFArc = class(TsgDXFCircle)
  private
    FEndAngle: TsgFloat;
    FStartAngle: TsgFloat;
    function RotPt(Angle: Extended): TFPoint;
  protected
    function GetClosed: Boolean; override;
    function GetEndAngle: TsgFloat;
    function GetStartAngle: TsgFloat;
    function GetHeight: Double; virtual;
    function GetEndingPoint: TFPoint;
    function GetEntType: TsgCADEntities; override;
    function GetStartingPoint: TFPoint;
    procedure SetHeight(const AValue: Double);
    procedure SetEndAngle(AValue: TsgFloat);
    procedure SetStartAngle(AValue: TsgFloat);
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Params(var A, B, AStart, AEnd, ASin, ACos: Double); override;
    function CircleParamsToXMLNode(const ANode: TsgNode;
      const AMode: TsgXMLModes = []): Integer; override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    function GetArea: Double; override;
    function GetLength: Double; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property EndAngle: TsgFloat read GetEndAngle write SetEndAngle;
    property EndPoint: TFPoint read GetEndingPoint;
    property StartAngle: TsgFloat read GetStartAngle write SetStartAngle;
    property StartPoint: TFPoint read GetStartingPoint;
  end;

  TsgDXFEllipse = class(TsgDXFArc)
  private
    FRadPt: TFPoint;
    FRatio: TsgFloat;
  protected
    FIsExtruded: Boolean;
    function GetAxisAngle: Double;
    function GetAxisAngleRad: Double;
    function GetRadPt: TFPoint;
    function GetRatio: TsgFloat;
    function GetEntType: TsgCADEntities; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Params(var A, B, AStart, AEnd, ASin, ACos: Double); override;
    procedure SetAxisAngle(const AAngle: Double);
    procedure SetAxisAngleRad(const AAngle: Double);
    procedure SetRatio(AValue: TsgFloat);
    procedure SetRadPt(AValue: TFPoint);
    function CircleParamsToXMLNode(const ANode: TsgNode;
      const AMode: TsgXMLModes = []): Integer; override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    function GetArea: Double; override;
    function GetLength: Double; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property Angle: TsgFloat read GetAxisAngleRad;
    property EndPoint: TFPoint read GetRadPt write SetRadPt;
    property RadPt: TFPoint read GetRadPt write SetRadPt;
    property Ratio: TsgFloat read GetRatio write SetRatio;
  end;

  PsgHatchPatternData = ^TsgHatchPatternData;

  TsgHatchPatternData = record
    LineAngle: Double;
    BaseP: TFPoint;
    Offset: TFPoint;
    DashNum: Integer;
    Lines: TsgDoubleList;
    IsDash: Boolean;
  end;

  Tsg2DCurve = class(TsgListObject)
  protected
    procedure Assign(const AVal: Tsg2DCurve); virtual;
    procedure ClearPoints; virtual;
    function GetCount: Integer; virtual;
    function GetEndPoint: TF2DPoint; virtual;
    function GetEdgeType: Byte; virtual;
    function GetPoints(const AIndex: Integer): TF2DPoint; virtual;
    function GetStartPoint: TF2DPoint; virtual;
    procedure Loaded; virtual;
    procedure Reverse(ANeedLoad: Boolean); virtual;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    function IsEdgeEqual(const ACurve: Tsg2DCurve): Boolean; virtual;
    property EdgeType: Byte read GetEdgeType;
    property Count: Integer read GetCount;
    property EndPoint: TF2DPoint read GetEndPoint;
    property Points[const AIndex: Integer]: TF2DPoint read GetPoints;
    property StartPoint: TF2DPoint read GetStartPoint;
  end;

  Tsg2DLine = class(Tsg2DCurve)
  private
    FEndPoint: TF2DPoint;
    FStartPoint: TF2DPoint;
  protected
    procedure Assign(const AVal: Tsg2DCurve); override;
    function GetCount: Integer; override;
    function GetEdgeType: Byte; override;
    function GetEndPoint: TF2DPoint; override;
    function GetPoints(const AIndex: Integer): TF2DPoint; override;
    function GetStartPoint: TF2DPoint; override;
    procedure Reverse(ANeedLoad: Boolean); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    function IsEdgeEqual(const ACurve: Tsg2DCurve): Boolean; override;
    procedure SetEndPoint(const AVal: TF2DPoint);
    procedure SetStartPoint(const AVal: TF2DPoint);
  end;

  Tsg2DPoints = class(Tsg2DCurve) // abstruct class by container FPoints
  private
    FPoints: TF2DPointList;
    function GetPointsCount: Integer;
  protected
    procedure Assign(const AVal: Tsg2DCurve); override;
    procedure ClearPoints; override;
    function GetCount: Integer; override;
    function GetEndPoint: TF2DPoint; override;
    function GetPoints(const AIndex: Integer): TF2DPoint; override;
    function GetStartPoint: TF2DPoint; override;
    procedure Loaded; override;
  public
    destructor Destroy; override;
  end;

  Tsg2DArc = class(Tsg2DPoints)
  private
    FCenterPoint: TF2DPoint;
    FEndParam: TsgFloat;
    FFlag: Byte;
    FRadius: TsgFloat;
    FStartParam: TsgFloat;
    function GetCounterClockWise: Boolean;
    procedure SetCounterClockWise(const AVal: Boolean);
  protected
    procedure Assign(const AVal: Tsg2DCurve); override;
    function GetCount: Integer; override;
    function GetEdgeType: Byte; override;
    function GetParamByAngle(const Angle: Double): Double; virtual;
    procedure Loaded; override;
    procedure Reverse(ANeedLoad: Boolean); override;
    procedure Params(var A, B, ASin, ACos: Double); virtual;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    destructor Destroy; override;
    function IsEdgeEqual(const ACurve: Tsg2DCurve): Boolean; override;
    property CenterPoint: TF2DPoint read FCenterPoint write FCenterPoint;
    property CounterClockWise: Boolean read GetCounterClockWise
      write SetCounterClockWise;
    property EndParam: TsgFloat read FEndParam write FEndParam;
    property Radius: TsgFloat read FRadius write FRadius;
    property StartParam: TsgFloat read FStartParam write FStartParam;
  end;

  Tsg2DEllipse = class(Tsg2DArc)
  private
    FMajorPoint: TF2DPoint;
    function GetIsAngleInParam: Boolean;
    procedure SetIsAngleInParam(const AVal: Boolean);
  protected
    procedure Assign(const AVal: Tsg2DCurve); override;
    function GetEdgeType: Byte; override;
    function GetParamByAngle(const Angle: Double): Double; override;
    procedure Params(var A, B, ASin, ACos: Double); override;
    procedure Reverse(ANeedLoad: Boolean); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    function IsEdgeEqual(const ACurve: Tsg2DCurve): Boolean; override;
    property IsAngleInParam: Boolean read GetIsAngleInParam
      write SetIsAngleInParam;
    property MajorPoint: TF2DPoint read FMajorPoint write FMajorPoint;
  end;

  Tsg2DPolyline = class(Tsg2DPoints)
  private
    FBulges: TsgSingleList;
    FProps: Byte;
    FVertexes: TF2DPointList;
    procedure ApplyBulge(const AP1, AP2: TF2DPoint; const ABulge: Double);
    function GetBulge(const AIndex: Integer): Single;
    function GetBulgesCount: Integer;
    function GetClosed: Boolean;
    function GetHasBulge: Boolean;
    function GetVertex(const AIndex: Integer): TF2DPoint;
    function GetVertexesCount: Integer;
    procedure SetBulge(const AIndex: Integer; const AVal: Single);
    procedure SetClosed(const AVal: Boolean);
    procedure SetVertex(const AIndex: Integer; const APoint: TF2DPoint);
  protected
    procedure Assign(const AVal: Tsg2DCurve); override;
    function GetEndPoint: TF2DPoint; override;
    function GetEdgeType: Byte; override;
    procedure Loaded; override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property Bulges[const AIndex: Integer]: Single read GetBulge write SetBulge;
    property Vertexes[const AIndex: Integer]: TF2DPoint read GetVertex
      write SetVertex;
    property BulgesCount: Integer read GetBulgesCount;
    property VertexesCount: Integer read GetVertexesCount;
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure Clear;
    procedure AddBulge(const AVal: Single);
    procedure AddVertex(const APoint: TF2DPoint);
    function GetLastVertex: PF2DPoint;
    function IsEdgeEqual(const ACurve: Tsg2DCurve): Boolean; override;
    property Closed: Boolean read GetClosed write SetClosed;
    property HasBulge: Boolean read GetHasBulge;
  end;

  Tsg2DSpline = class(Tsg2DPoints)
  private
    FControls: TF2DPointList;
    FKnots: TsgSingleList;
    FParams: Cardinal;
    FWeights: TsgSingleList;
    function GetDegree: Byte;
    function GetKnot(const AIndex: Integer): Single;
    function GetPeriodic: Boolean;
    function GetRational: Boolean;
    function GetControl(const AIndex: Integer): TF2DPoint;
    function GetControlsCount: Integer;
    function GetKnotsCount: Integer;
    function GetWeight(const AIndex: Integer): Single;
    function GeWeightsCount: Integer;
    procedure SetControl(const AIndex: Integer; const APoint: TF2DPoint);
    procedure SetKnot(const AIndex: Integer; const AVal: Single);
    procedure SetDegree(const Value: Byte);
    procedure SetRational(const Value: Boolean);
    procedure SetPeriodic(const Value: Boolean);
    procedure SetWeight(const AIndex: Integer; const Value: Single);
  protected
    procedure Assign(const AVal: Tsg2DCurve); override;
    procedure Loaded; override;
    function GetEdgeType: Byte; override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property Controls[const AIndex: Integer]: TF2DPoint read GetControl
      write SetControl;
    property Knots[const AIndex: Integer]: Single read GetKnot write SetKnot;
    property Weights[const AIndex: Integer]: Single read GetWeight
      write SetWeight;
    property ControlsCount: Integer read GetControlsCount;
    property KnotsCount: Integer read GetKnotsCount;
    property WeightsCount: Integer read GeWeightsCount;
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure AddControl(const APoint: TF2DPoint);
    procedure AddKnot(const AVal: Single);
    procedure AddWeight(const AVal: Single);
    function GetLastVertex: PF2DPoint;
    function IsEdgeEqual(const ACurve: Tsg2DCurve): Boolean; override;
    property Degree: Byte read GetDegree write SetDegree;
    property Periodic: Boolean read GetPeriodic write SetPeriodic;
    property Rational: Boolean read GetRational write SetRational;
  end;

  Tsg2DBoundaryList = class(TsgListObject)
  private
    FBoundaryType: Byte;
    FObjects: TList;
    function GetCount: Integer;
    function GetItem(const AIndex: Integer): Tsg2DCurve;
    procedure SetCount(const AValue: Integer);
    procedure SetItem(const AIndex: Integer; const AValue: Tsg2DCurve);
  protected
    function IsTextBox: Boolean;
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure AssignBoundary(const AObject: TObject);
    procedure Add(const AValue: Tsg2DCurve);
    procedure Clear;
    procedure CopyFrom(const AList: Tsg2DBoundaryList;
      const AIndex, ACount: Integer);
    procedure Delete(const AIndex: Integer);
    procedure Insert(const AIndex: Integer; const AValue: Tsg2DCurve);
    function IsBoundaryEqual(const AList: Tsg2DBoundaryList): Boolean;
    property Count: Integer read GetCount write SetCount;
    property Items[const AIndex: Integer]: Tsg2DCurve read GetItem
      write SetItem; default;
    property BoundaryType: Byte read FBoundaryType write FBoundaryType;
  end;

  TsgCADPolyPolygon = class(TsgDXFObjectEntityLineType)
  private
    FBox: TFRect;
    FBoundaryPolylines: TList;
  protected
    function ApplyAngle(const AngleRel: Double): Boolean; virtual;
    function ApplyScale(const AScaleRel: Double): Boolean; virtual;
    function CanDraw: Boolean; override;
    procedure CalcFMatrix; virtual;
    procedure ClearBoundaryData; virtual;
    procedure CloseBoundary; virtual;
    function BoxTransformation(AConverter: TsgDXFConverter; const ABox: TFRect)
      : TFRect; virtual;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetBox: TFRect; override;
    function GetEntType: TsgCADEntities; override;
    function GetHatchName: string; virtual;
    function GetSolidFill: Boolean; virtual;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure MakeBorderPolylines(AConverter: TsgDXFConverter); virtual;
    procedure ParseLines; virtual;
    procedure SetHatchName(const AHatchName: string); virtual;
    procedure SetSolidFill(const Value: Boolean); virtual;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean; override;
    property Boundaries: TList read FBoundaryPolylines;
    property HatchName: string read GetHatchName write SetHatchName;
    property SolidFill: Boolean read GetSolidFill write SetSolidFill;
  end;

  TsgCADGradientPolygon = class(TsgCADPolyPolygon)
  private
    FGradientColor: array [0 .. 1] of TsgColorCAD;
    FGradientAngle: TsgFloat;
    FGradientUseCenter: Boolean;
  protected
    FType: TsgGradientType;
    function GetEntType: TsgCADEntities; override;
    function GetHatchName: string; override;
    function GetGradientName: string;
    function GetGradientAngle: TsgFloat;
    function GetGradientColor(const AIndex: Byte): TColor;
    function GetGradientColorCAD(const AIndex: Byte): TsgColorCAD;
    procedure SetGradientAngle(const Value: TsgFloat);
    procedure SetGradientName(const AName: string);
    procedure SetGradientColorCAD(const AIndex: Byte; const Value: TsgColorCAD);
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property GradientAngle: TsgFloat read GetGradientAngle
      write SetGradientAngle;
    property GradientColor[const AIndex: Byte]: TColor read GetGradientColor;
    property GradientColorCAD[const AIndex: Byte]: TsgColorCAD
      read GetGradientColorCAD write SetGradientColorCAD;
    property GradientName: string read GetGradientName write SetGradientName;
    property GradientUseCenter: Boolean read FGradientUseCenter
      write FGradientUseCenter;
  end;

  TsgCADBoundaryData = class(TsgDXFEntity)
  private
    FBoundaries: TList;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;

    function CanUseBoundaryList(const AList: Tsg2DBoundaryList;
      const ASolidFill: Boolean): Boolean;
    function GetIndexOfNeighbour(const AList: Tsg2DBoundaryList;
      const ALastPoint: TF2DPoint; const AStartIndex: Integer;
      const AAccuracy: Double; var ALastPointType: Boolean): Integer;
    function GenerateListOfBoundaries(const AList: TList;
      AExplodePolyline: Boolean = False): TFRect;
    procedure MakeBorderPolylines(const AConverter: TsgDXFConverter;
      const ABoundaryPolylines: TList; const ASolidFill: Boolean);

    function GetNodeName: string; override;
    function BoundaryToXMLNode(const ABoundary: Tsg2DBoundaryList;
      const ANode: TsgNode): Integer;
    function BoundaryToFromNode(const ABoundary: Tsg2DBoundaryList;
      const ANode: TsgNodeSample; const AResult: IsgResultNode = nil): Integer;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function AddBoundaryList(const AFlags: Byte = 0): Tsg2DBoundaryList;
    procedure CopyBoundaries(const ABoundaryData: TsgCADBoundaryData);
    procedure ClearBoundaries(const AClearCapacity: Boolean = True);
    property Boundaries: TList read FBoundaries;
  end;

  TsgCADHatchPatternData = class(TsgDXFEntity)
  private
    FAngle: Double;
    FName: string;
    FScale: Double;
    FPatterns: TList;
    procedure HatchLine(AList: TsgDoubleList; Pt1, Pt2, BasePt: TFPoint;
      DottedSingPts: TFPointList);
    procedure NewLineWithBasePAndAddList(AList: TList;
      APoint1, APoint2, ABasePoint: TF2DPoint);
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;

    procedure ApplyAngle(const AngleRel: Double);
    procedure ApplyScale(const AScaleRel: Double);
    function ParseLines(const AParsedLines: TFPointList;
      const ABoundaryPolylines: TList; const ABox: TFRect;
      const AHatchStyle: TsgHatchStyle): TsgHatchStyle;
    function GetNodeName: string; override;
    function HatchPatternDataToXMLNode(const AData: PsgHatchPatternData;
      const ANode: TsgNode): Integer;
    function HatchPatternDataFromToXMLNode(const AData: PsgHatchPatternData;
      const ANode: TsgNodeSample; const AResult: IsgResultNode = nil): Integer;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function AddPatternData(const ABasePoint: TFPoint; const Angle: Double;
      const ASign: Integer): PsgHatchPatternData;
    procedure CopyPatterns(const APatterns: TsgCADHatchPatternData);
    procedure ClearPatterns(const AClearCapacity: Boolean = True);
    procedure DoAngle(const AValue: Double);
    procedure DoScale(const AValue: Double);
    property Angle: Double read FAngle write FAngle;
    property Name: string read FName write FName;
    property Scale: Double read FScale write FScale;
    property Patterns: TList read FPatterns;
  end;

  TsgCADCurvePolygon = class(TsgCADGradientPolygon)
  private
    FBoundaryData: TsgCADBoundaryData;
    FElevation: TFPoint;
    FExtrusion: TFPoint;
    FMatrix: TFMatrix;
    function GetBoundaryData(const AIndex: Integer): Tsg2DBoundaryList;
    function GetBoundaryDataCount: Integer;
    function GetBoundaryDataLast: Tsg2DBoundaryList;
  protected
    procedure CalcFMatrix; override;
    procedure CopyBoundaryData(const APolygon: TsgCADCurvePolygon);
    procedure ChechBoundaryData(const AHatch: TsgCADCurvePolygon);
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function BoxTransformation(AConverter: TsgDXFConverter; const ABox: TFRect)
      : TFRect; override;
    function GenerateListOfBoundaries(const AList: TList;
      AExplodePolyline: Boolean = False): TFRect;
    function GetElevation: TFPoint;
    function GetEntType: TsgCADEntities; override;
    function GetExtrusion: TFPoint; override;
    function GetFillColor: TsgColorCAD; virtual;
    function GetMatrix: TFMatrix;
    function GetOffset: TFPoint; virtual;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); override;
    function IsInvoke(AConverter: TsgDXFConverter): Boolean; override;
    procedure ListNotify(Ptr: Pointer; Action: TListNotification); override;
    procedure MakeBorderPolylines(AConverter: TsgDXFConverter); override;
    procedure SetElevation(const Value: TFPoint);
    procedure SetExtrusion(const Value: TFPoint); override;
    procedure SetFillColor(const Value: TsgColorCAD); virtual;
    procedure SetOffset(const Value: TFPoint); virtual;
    function UseMatrix: Boolean; virtual;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;

    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; override;

    procedure ClearBoundaryData; override;
    function GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean; override;
    function AddBoundaryList(const AFlags: Byte = 0): Tsg2DBoundaryList;
    property BoundaryData[const AIndex: Integer]: Tsg2DBoundaryList
      read GetBoundaryData;
    property BoundaryDataCount: Integer read GetBoundaryDataCount;
    property BoundaryDataLast: Tsg2DBoundaryList read GetBoundaryDataLast;
    property Elevation: TFPoint read GetElevation write SetElevation;
    property Extrusion: TFPoint read GetExtrusion write SetExtrusion;
    property FillColor: TsgColorCAD read GetFillColor write SetFillColor;
    property Offset: TFPoint read GetOffset Write SetOffset;
  end;

  TsgCADHatch = class(TsgCADCurvePolygon)
  private
    FHatchPatternData: TsgCADHatchPatternData;
    FHatchStyles: Integer;
    // Ptt - pattern values
    FParsedLines: TFPointList;
    FLineWeight: Double;
    function GetHatchStyle: TsgHatchStyle;
    function GetHatchPatternData: TList;
    procedure SetHatchStyle(const Value: TsgHatchStyle);
  protected
    function AddPatternData(const ABasePoint: TFPoint; const Angle: Double;
      const ASign: Integer = 1): PsgHatchPatternData;
    procedure ApplyFillStyle(const AFillStyle: TsgFillStyle;
      const ABasePoint: TFPoint);
    function ApplyAngle(const AngleRel: Double): Boolean; override;
    function ApplyScale(const AScaleRel: Double): Boolean; override;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetEntType: TsgCADEntities; override;
    function GetFillStyle: TsgFillStyle;
    function GetHatchName: string; override;
    function GetLineWeight: Double; override;
    function GetPatternAngle: TsgFloat;
    function GetPatternScale: TsgFloat;
    function GetSolidFill: Boolean; override;
    procedure ListNotify(Ptr: Pointer; Action: TListNotification); override;
    procedure ParseLines; override;
    procedure SetFillStyle(const Value: TsgFillStyle);
    procedure SetFillStyleWithApplyStyle(const Value: TsgFillStyle);
    procedure SetHatchName(const AHatchName: string); override;
    procedure SetLineWeight(Value: Double); override;
    procedure SetPatternAngle(const AVal: TsgFloat);
    procedure SetPatternScale(const AVal: TsgFloat);
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property PatternData: TsgCADHatchPatternData read FHatchPatternData;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;

    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; override;

    function GetThickness: Double; override;
    // property HatchLines: TList read FHatchPatternData;
    procedure ClearHatchPatternData;
    procedure CopyHatchPatternData(const AHatch: TsgCADHatch);
    property FillStyle: TsgFillStyle read GetFillStyle
      write SetFillStyleWithApplyStyle;
    property HatchPatternData: TList read GetHatchPatternData;
    property HatchStyle: TsgHatchStyle read GetHatchStyle write SetHatchStyle;
    property ParsedLines: TFPointList read FParsedLines;
    property PatternAngle: TsgFloat read GetPatternAngle write SetPatternAngle;
    property PatternScale: TsgFloat read GetPatternScale write SetPatternScale;
  end;

  TsgCADMPolygon = class(TsgCADHatch)
  private
    FOffset: TF2DPoint;
    FFillColor: TsgColorCAD;
  protected
    procedure CalcFMatrix; override;
    function GetFillColor: TsgColorCAD; override;
    function GetEntType: TsgCADEntities; override;
    function GetOffset: TFPoint; override;
    function GetSolidFill: Boolean; override;
    procedure SetFillColor(const Value: TsgColorCAD); override;
    procedure SetOffset(const Value: TFPoint); override;
    procedure SetSolidFill(const Value: Boolean); override;
    function UseMatrix: Boolean; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
  end;

  (*
    TsgDXFGradient = class(TsgCADCurvePolygon)
    private
    FPData1: TF2DPoint;
    FPData2: TF2DPoint;
    FRadius: Double;
    FGFlags: Byte;
    FColors: TList;
    FPositions: TList;
    FMatrix: PFMatrix;
    protected
    function GetAbsParam: Boolean;
    function GetEntType: TsgCADEntities; override;
    function GetHatchName: string; override;
    function GetPData1: TFPoint;
    function GetPData2: TFPoint;
    function GetRadius: Double;
    function GetTransform: TFMatrix;
    procedure SetAbsParams(const Value: Boolean);
    procedure SetPData1(const Value: TFPoint);
    procedure SetPData2(const Value: TFPoint);
    procedure SetRadius(const Value: Double);
    procedure SetTransform(const Value: TFMatrix);
    public
    constructor Create; override;
    destructor Destroy; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function IsHorizontal: Boolean;
    function IsSpheric: Boolean;
    function IsVertical: Boolean;
    function HasMatrix: Boolean;
    property Colors: TList read FColors;
    property Positions: TList read FPositions;
    property AbsParams: Boolean Read GetAbsParam write SetAbsParams;
    property Point1: TFPoint read GetPData1 write SetPData1;
    property Point2: TFPoint read GetPData2 write SetPData2;
    property PointC: TFPoint read GetPData1 write SetPData1;
    property PointF: TFPoint read GetPData2 write SetPData2;
    property Radius: Double read GetRadius write SetRadius;
    property Transform: TFMatrix read GetTransform write SetTransform;
    end;
  *)
  TsgStyleFillUnits = (sfUserSpaceOnUse, sfObjectBoundingBox);
  TsgStyleGradSpreadMethod = (smPad, smReflect, smRepeat);

  TsgCADStyleFill = class
  private
    FFlags: Byte;
    FRef: TsgCADStyleFill;
    FTransform: PFMatrix;
    FValues: array [0 .. 4] of Double;
  protected
    function GetLocal: Boolean;
    function GetTransform: TFMatrix;
    function GetUnits: TsgStyleFillUnits;
    function GetV0: Double;
    function GetV1: Double;
    function GetV2: Double;
    function GetV3: Double;
    function GetV4: Double;
    function GetPoint1: TFPoint;
    procedure SetLocal(const Value: Boolean);
    procedure SetRef(const Value: TsgCADStyleFill); virtual;
    procedure SetTransform(const Value: TFMatrix);
    procedure SetUnits(const Value: TsgStyleFillUnits);
    procedure SetV0(const Value: Double);
    procedure SetV1(const Value: Double);
    procedure SetV2(const Value: Double);
    procedure SetV3(const Value: Double);
    procedure SetV4(const Value: Double);
    procedure SetPoint1(const Value: TFPoint);
  public
    constructor Create; virtual;
    destructor Destroy; override;
    procedure Assign(const AObj: TObject); virtual;
    procedure CheckParams; virtual;
    property Local: Boolean read GetLocal write SetLocal;
    property Units: TsgStyleFillUnits read GetUnits write SetUnits;
    property Transform: TFMatrix read GetTransform write SetTransform;
    property HRef: TsgCADStyleFill read FRef write SetRef;
    property X1: Double read GetV0 write SetV0;
    property Y1: Double read GetV1 write SetV1;
    property Point1: TFPoint read GetPoint1 write SetPoint1;
  end;

  TsgClassOfCADStyleFill = class of TsgCADStyleFill;

  TsgCADStyleGradient = class(TsgCADStyleFill)
  private
    FStops: TsgSingleList;
  protected
    function GetLinear: Boolean;
    function GetSpreadMethod: TsgStyleGradSpreadMethod;
    function GetStopsCount: Integer;
    function GetStopList: TsgSingleList;
    function GetPoint2: TFPoint;
    procedure SetLinear(const Value: Boolean);
    procedure SetRef(const Value: TsgCADStyleFill); override;
    procedure SetSpreadMethod(const Value: TsgStyleGradSpreadMethod);
    procedure SetPoint2(const Value: TFPoint);
  public
    destructor Destroy; override;
    procedure Assign(const AObj: TObject); override;
    procedure AddStops(const AColor: Integer; const AOffset: Double);
    procedure CheckParams; override;
    procedure GetPositionColors(const APos: TsgSingleList;
      const AColor: TsgIntegerList);
    function HasStops: Boolean;
    property SpreadMethod: TsgStyleGradSpreadMethod read GetSpreadMethod
      write SetSpreadMethod;
    property Linear: Boolean read GetLinear write SetLinear;
    property X2: Double read GetV2 write SetV2;
    property Y2: Double read GetV3 write SetV3;
    property CX: Double read GetV0 write SetV0;
    property CY: Double read GetV1 write SetV1;
    property FX: Double read GetV2 write SetV2;
    property FY: Double read GetV3 write SetV3;
    property R: Double read GetV4 write SetV4;

    property Point2: TFPoint read GetPoint2 write SetPoint2;
    property PointC: TFPoint read GetPoint1 write SetPoint1;
    property PointF: TFPoint read GetPoint2 write SetPoint2;
  end;

  TsgCADStylePattern = class(TsgCADStyleFill)
  private
    FBox: TFRect;
    FEntities: TList;
    FViewBox: PsgViewBox;
    function GetCount: Integer;
    function GetEntity(const AIndex: Integer): TsgDXFEntity;
  protected
    function GetContainerSize: TFRect;
    function GetContainerBox: TFRect;
    // function GetContainerByHatch: TList;
    function GetContentUnits: TsgStyleFillUnits;
    function GetSize: TFPoint;
    function GetViewBox: TsgViewBox;
    procedure SetContentUnits(const Value: TsgStyleFillUnits);
    procedure SetRef(const Value: TsgCADStyleFill); override;
    procedure SetSize(const Value: TFPoint);
    procedure SetViewBox(const Value: TsgViewBox);
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure Assign(const AObj: TObject); override;
    procedure AddEntity(const AEntity: TsgDXFEntity);
    procedure CheckParams; override;
    procedure Iterate(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc);
    procedure Loaded(const AConverter: TsgDXFConverter);
    property Box: TFRect read FBox;
    property ContentUnits: TsgStyleFillUnits read GetContentUnits
      write SetContentUnits;
    property Count: Integer read GetCount;
    property ContainerBox: TFRect read GetContainerBox;
    property ContainerSize: TFRect read GetContainerSize;
    property Entities[const AIndex: Integer]: TsgDXFEntity
      read GetEntity; default;
    property Width: Double read GetV2 write SetV2;
    property Height: Double read GetV3 write SetV3;
    property ViewBox: TsgViewBox read GetViewBox write SetViewBox;
    property Size: TFPoint read GetSize write SetSize;
  end;

  TsgCADFill = class(TsgCADCurvePolygon)
  private
    FCADFillFlags: Byte;
    FStyleFill: TsgCADStyleFill;
    FImage: TBitmap;
    function GetStyleFill: TsgCADStyleFill;
    function GetBackground: TColor;
    function GetUseBuffer: Boolean;
    procedure SetStyleFill(const Value: TsgCADStyleFill);
    procedure SetUseBuffer(const Value: Boolean);
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetBush(const W, H: Integer; AClass: TClass): TBitmap;
    function GroupExists: Boolean; override;
    function GroupFill(AConverter: TsgDXFConverter = nil): Boolean; override;
    function GroupHasAddedEntities: Boolean; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure SetBackgroundColor(const ABmp: TBitmap);
    procedure SetTransparentColor(const ABmp: TBitmap);
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function CreateBMPFill(const AMatrix: TFMatrix;
      const AClass: TClass): Boolean;
    function CreateBMPPattern(AWidth, AHeight: Integer;
      const AClass: TClass): TBitmap;
    function ConvertToImageEnt(const AConverter: TsgDXFConverter)
      : TsgDXFImageEnt;
    property Background: TColor read GetBackground;
    property BMPImage: TBitmap read FImage;
    property StyleFill: TsgCADStyleFill read GetStyleFill write SetStyleFill;
    property UseBuffer: Boolean read GetUseBuffer write SetUseBuffer;
  end;

  TsgDXFTable = class(TsgDXFGroupName)
  private
    FSortEntList: TsgStringList;
  protected
    function AddItem(const AItem: TsgDXFEntity): Integer; override;
    procedure ApplyBox; override;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetComplex: Boolean; override;
    function RenameItem(const AItem: TsgDXFEntity;
      const NewName: string): Boolean;
    function DeleteItem(const AItem: TsgDXFEntity): Integer; override;
    procedure SetEntity(const AIndex: Integer;
      const AEntity: TsgDXFEntity); override;

    procedure Link(AConverter: TsgDXFConverter); override;
    procedure ListNotify(Ptr: Pointer; Action: TListNotification); override;

    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function FindEntByName(const AName: string): TsgDXFEntity; override;
    // functions of IsgListOfEntities
    procedure Clear(const ADoFree: Boolean = True); override;
  end;

  TsgDXFBlockRecords = class(TsgDXFTable)
  private
    FBlocks: TsgDXFGroup;
    function GetBlocks: TsgDXFGroup;
    procedure SetBlocks(const Value: TsgDXFGroup);
  protected
    function GetName: string; override;
    procedure Link(AConverter: TsgDXFConverter); override;
    property Blocks: TsgDXFGroup read GetBlocks write SetBlocks;
  public
    constructor Create; override;
    function AddEntity(const AEntity: TsgDXFEntity): Integer; override;
    procedure Clear(const ADoFree: Boolean = True); override;
    function DeleteEntity(const AIndex: Integer): TsgDXFEntity; override;
    procedure ExchangeEntity(AIndex1, AIndex2: Integer); override;
    function GetCount: Integer; override;
    function GetEntity(const AIndex: Integer): TsgDXFEntity; override;
    function IndexOfEntity(const AEntity: TsgDXFEntity): Integer; override;
    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; override;
    procedure SetEntity(const AIndex: Integer;
      const AEntity: TsgDXFEntity); override;

    function FindEntByName(const AName: string): TsgDXFEntity; override;
    function IndexOfName(const AName: string): Integer; override;
  end;

  TsgDXFBlock = class(TsgDXFGroupName)
  private
    FBlockRecord: TsgDXFBlockRecord;
    // FFlags: Integer;
    FOffset: TFPoint;
    FReferences: TsgList;
    FXref: TsgDXFXref;
    FXrefPath: string;
    FLayout: TsgDXFEntity;
    function IterateEx(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc): TList;
    procedure AddFromXrefPath(AConverter: TsgDXFConverter);
    procedure CheckAttdefFlag;
    // procedure CheckSpecPaperSpaceName;
    function GetBlockRecord: TsgDXFBlockRecord;
    function GetLoaded: Boolean;
    function GetReferences: TsgList;
    // function GetSpecPaperSpace: Boolean;{$IFDEF SGDEL_6} deprecated{$IFDEF SGDEL_2009}'This procedure is obsolete and will be deleted in the next version. Please, use the following property - Layout!'{$ENDIF};{$ENDIF}
    procedure SetLoaded(const Value: Boolean);
    // procedure SetSpecPaperSpace(const Value: Boolean);
    function GetLayout: TsgDXFEntity;
    procedure SetLayout(const Value: TsgDXFEntity);
  protected
    function GetComplex: Boolean; override;
    function GetXrefPath: string;
    procedure ApplyBox; override;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure ListNotify(Ptr: Pointer; Action: TListNotification); override;
    procedure SetXrefPath(const Value: string);
{$IFDEF SG_BTI}
    function GetExtendedData: TObject; virtual;
{$ENDIF}
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    // functions of IsgListOfEntities
    function AddEntity(const AEntity: TsgDXFEntity): Integer; override;
    procedure Clear(const ADoFree: Boolean = True); override;
    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; override;
    property BlockRecord: TsgDXFBlockRecord read GetBlockRecord;
    function IsBlockIntetnal: Boolean;
    function IsBlockByXRef: Boolean;
    function IsBlockXrefOverlay: Boolean;
    function IsAcadTableBlock: Boolean;
    function IsModalSpaceBlock: Boolean;
    property IsLoaded: Boolean read GetLoaded write SetLoaded;
    // not documented, only for internal using (!)
    property Offset: TFPoint read FOffset write FOffset;
    property References: TsgList read GetReferences;
    // property SpecPaperSpace: Boolean read GetSpecPaperSpace;  // not documented, only for internal using (!)
    property Layout: TsgDXFEntity read GetLayout write SetLayout;
    property Xref: TsgDXFXref read FXref;
    property XrefPath: string read GetXrefPath write SetXrefPath;
  end;

  TsgDXFSection = class(TsgDXFTable)
  protected
    procedure ChangeHandle(AConverter: TsgDXFConverter); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    function IsTablesBelongSection(ATable: TConvSection): Boolean; virtual;
  end;

  TsgDXFSectionTables = class(TsgDXFSection)
  protected
    function IsTablesBelongSection(ATable: TConvSection): Boolean; override;
  public
    constructor Create; override;
  end;

  TsgDXFSectionObjects = class(TsgDXFSection)
  protected
    function IsTablesBelongSection(ATable: TConvSection): Boolean; override;
  public
    constructor Create; override;
  end;

  TsgDXFSectionBlocks = class(TsgDXFSection)
  public
    constructor Create; override;
  end;

  TsgDXFSectionForXMLExport = class(TsgDXFSection)
  protected
    function AddItem(const AItem: TsgDXFEntity): Integer; override;
    function DeleteItem(const AItem: TsgDXFEntity): Integer; override;
    procedure Link(AConverter: TsgDXFConverter); override;
  public
    constructor CreateByConverter(const AConverter: TsgDXFConverter); virtual;
    function FindEntByName(const AName: string): TsgDXFEntity; override;
  end;

  TsgDXFSectionForXMLExportClass = class of TsgDXFSectionForXMLExport;

  TsgDXFSectionHeader = class(TsgDXFSectionForXMLExport)
  private
    FAccess: TsgDXFEntitySample;
  protected
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    class function ToXMLNodeDimProps(const AProps: TsgDimStyle;
      const ANode: TsgNode; const AMode: TsgXMLModes = []): Integer;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    class function FromXMLNodeDimProps(var AProps: TsgDimStyle;
      const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil): Integer;
  public
    constructor CreateByConverter(const AConverter: TsgDXFConverter); override;
    destructor Destroy; override;
    function GetPHeadVarStruct(const AGetDefault: Boolean = True)
      : PsgHeadVarStruct;
  end;

  TsgDXFSectionEntities = class(TsgDXFSectionForXMLExport)
  private
    function GetEntities: TsgDXFEntity;
  public
    constructor CreateByConverter(const AConverter: TsgDXFConverter); override;
    function FromXML(const ANode: TsgNodeSample;
      const AResult: IsgResultNode = nil): Integer; override;
    function ToXML(const AParrentNode: TsgNode;
      const AMode: TsgXMLModes = cnstDefaultXMLMode): TsgNode; override;
  end;

  TsgDXFInsert = class(TsgDXFCustomVertex)
  private
    FAttribs: TListNotify;
    FBlockRecord: TsgDXFBlockRecord;
    FExtrusion: TFPoint;
    FLineWeight: Double;
    FOwnerInsert: TsgDXFInsert;
    FSceneElement: Integer;
    function GetBlock: TsgDXFBlock;
    function GetDelayedLoadAttribs: Boolean;
    procedure SetDelayedLoadAttribs(const Value: Boolean);
    procedure LinkBlockRecord(AConverter: TsgDXFConverter);
  protected
    FAngle: Single;
    FBox: TFRect;
    FMatrix: TFMatrix;
    FScale: TFPoint;
    procedure AssignAttrib(Dest, Source: TsgDXFEntity); virtual;
    procedure CalculateMatrix;
    function CheckBlock(AConverter: TsgDXFConverter): Boolean;
    procedure ClearReferences; override;
    procedure CopyItems(const ASource: TsgDXFEntity); virtual;
    procedure FreeReferences; override;
    procedure DoDelayedLoad(AConverter: TsgDXFConverter); virtual;
    function GetAngle: Single; virtual;
    function GetBlockOffset: TFPoint; virtual;
    function GetBox: TFRect; override;
    function GetCount: Integer; override;
    function GetEntity(const AIndex: Integer): TsgDXFEntity; override;
    function GetEntType: TsgCADEntities; override;
    function GetHasAttribs: Boolean;
{$IFDEF SG_BTI}
    function GetExtendedData: PsgExtendedData; virtual;
    function GetExtendedBlockData: TsgExtendedBlockData; virtual;
    function GetOwnerConstruction: TsgDXFEntity; virtual;
    procedure GetArcsParams(var Arcs: TsgArcsParams); virtual;
    procedure GetPts(var APts: TsgPoints4); virtual;
    procedure GetPtsEx(const AList: TFPointList); virtual;
    procedure SetExtendedData(const Value: PsgExtendedData); virtual;
{$ENDIF}
    function GetExtrusion: TFPoint; override;
    function GetLineWeight: Double; override;
    function GetName: string; override;
    function GetNodeName: string; override;
    function GetScale: TFPoint;
    class function GetXMLNameOfSceneElement: string;
    procedure InitializeMatrix; virtual;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); override;
    procedure OffsetAttribs(const ADelta: TFPoint);
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    procedure ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord); virtual;
    procedure ReloadAttribs(AConverter: TsgDXFConverter);
    procedure Resolve(AConverter: TsgDXFConverter);
    procedure RemoveReferenceNotification(const ARefObj: TsgDXFEntity);
      override;
    procedure SetAngle(const Value: Single); virtual;
    procedure SetBlock(const Value: TsgDXFBlock);
    procedure SetBlockRecord(const Value: TsgDXFBlockRecord); virtual;
    procedure SetExtrusion(const Value: TFPoint); override;
    procedure SetEntity(const AIndex: Integer;
      const AEntity: TsgDXFEntity); override;
    procedure SetLineWeight(Value: Double); override;
    procedure SetPoint(AValue: TFPoint); override;
    procedure SetScale(const Value: TFPoint); virtual;
    function ToXMLGeoData(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; virtual;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property DelayedLoadAttribs: Boolean read GetDelayedLoadAttribs
      write SetDelayedLoadAttribs;
    property SceneElement: Integer read FSceneElement write FSceneElement;
    // for internal using
  public
    constructor Create; override;
    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function Attrib(const S: string; var P: TFPoint): TsgDXFAttrib;
    procedure Clear(const ADoFree: Boolean = True); override;
    function EntName: string; override;
    function FindBlock(AConverter: TsgDXFConverter; const AName: string)
      : TsgDXFBlock;
    function GetMatrix: TFMatrix;
    function ExtractParamsFromMatrix2D(var P, S: TFPoint;
      var A: Double): Boolean;
    function IsInsert: Boolean; override; // evg
    function IsOnePixelOptimisationValid: Boolean; override; // evg
    function RealColor(AColor: TColor): TColor;
    function RealLayer: TsgDXFLayer;
    property Angle: Single read GetAngle write SetAngle;
    property Attribs: TListNotify read FAttribs;
    property Block: TsgDXFBlock read GetBlock write SetBlock;
    property BlockRecord: TsgDXFBlockRecord read FBlockRecord
      write SetBlockRecord;
    property Extrusion: TFPoint read GetExtrusion write SetExtrusion;
    property HasAttribs: Boolean read GetHasAttribs;
    property Scale: TFPoint read GetScale write SetScale;
    property OwnerInsert: TsgDXFInsert read FOwnerInsert;
  end;

  TsgDXFInsertXRef = class(TsgDXFInsert)
  private
    FNameFile: string;
    FOwner: TsgDXFEntity;
    FRealInsert: TsgDXFInsert;
  protected
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
  public
    property RealInsert: TsgDXFInsert read FRealInsert;
    property Owner: TsgDXFEntity read FOwner write FOwner;
  end;

  TsgCADClipInsert = class(TsgDXFInsert)
  private
  protected
    FClipBox: TFRect;
    function GetBox: TFRect; override;
    function GetClipBox: TFRect;
    procedure SetClipBox(const Value: TFRect);
    procedure SetPoint(AValue: TFPoint); override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property ClipBox: TFRect read GetClipBox write SetClipBox;
  end;

  TsgCADMInsert = class(TsgDXFInsert)
  private
    FNumCols: Word;
    FNumRows: Word;
    FColSpacing: Double;
    FRowSpacing: Double;
  protected
    function GetBox: TFRect; override;
    function GetColSpacing: Double;
    function GetNumCols: Integer;
    function GetNumRows: Integer;
    function GetRowSpacing: Double;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); override;
    procedure SetColSpacing(const Value: Double);
    procedure SetNumCols(const Value: Integer);
    procedure SetNumRows(const Value: Integer);
    procedure SetRowSpacing(const Value: Double);
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property NumCols: Integer read GetNumCols write SetNumCols;
    property NumRows: Integer read GetNumRows write SetNumRows;
    property ColSpacing: Double read GetColSpacing write SetColSpacing;
    property RowSpacing: Double read GetRowSpacing write SetRowSpacing;
  end;

  TsgMLineEntry = class(TsgDXFEntity)
  private
    FColor: TsgColorCAD;
    FLineTypeItem: TsgTableItem;
    FOffset: Double;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetColorCAD: TsgColorCAD; override;
    procedure SetColorCAD(const Value: TsgColorCAD); override;
    function GetLineType: TsgDXFLineType; override;
    procedure SetLineType(const AValue: TsgDXFLineType); override;
    procedure Link(AConverter: TsgDXFConverter); override;
  public
    constructor Create; override;
    property Offset: Double read FOffset write FOffset;
  end;

  TsgMLineStyle = class(TsgDXFCustomColor)
  private
    FEntries: TListNotify;
    function GetEntry(Index: Integer): TsgMLineEntry;
  protected
    procedure FreeReferences; override;
    function GetCount: Integer; override;
    function GetEntity(const AIndex: Integer): TsgDXFEntity; override;
  public
    constructor Create; override;
    procedure Clear(const ADoFree: Boolean = True); override;
    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    procedure NewEntry(AOffset: Double; AColor: TsgColorCAD;
      ALType: TsgDXFLineType);
    property Entries[Index: Integer]: TsgMLineEntry read GetEntry; default;
  end;

  TsgMVertex = class(TsgDXFEntity)
  private
    FPoint: TFPoint;
    FDirection: TFPoint;
    FMiter: TFPoint;
    FParams: TList;
    function GetPCount(Index: Integer): Integer;
    function GetParam(I1, I2: Integer): Single;
    function GetParamsCount: Integer;
    procedure SetParam(I1, I2: Integer; Value: Single);
    function GetParamsList: TList;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    property ParamsList: TList read GetParamsList;
  public
    constructor Create; override;
    procedure Add(Value: Single);
    procedure AssignEntity(Source: TsgDXFEntity); override;
    procedure Complete;
    procedure NewList;
    property Point: TFPoint read FPoint write FPoint;
    property Direction: TFPoint read FDirection write FDirection;
    property Miter: TFPoint read FMiter write FMiter;
    property ParamsCount: Integer read GetParamsCount;
    property PCounts[Index: Integer]: Integer read GetPCount;
    property Params[I1, I2: Integer]: Single read GetParam
      write SetParam; default;
  end;

  TsgCADMLine = class(TsgDXFInsert)
  private
    FFlags: Integer;
    FJustify: Byte;
    FItems: TListNotify;
    FStyle: TsgMLineStyle;
    FScaleFactor: Double;
    FStartPoint: TFPoint;
    function GetItem(Index: Integer): TsgMVertex;
    procedure SetFill;
  protected
    procedure CopyItems(const ASource: TsgDXFEntity); override;
    procedure FreeReferences; override;
    function GetItemsCount: Integer;
    function GetCount: Integer; override;
    function GetEntType: TsgCADEntities; override;
    function GetJustify: Byte;
    function GetScaleFactor: Double;
    function GetStyle: TsgMLineStyle;
    function GetFlags: Integer; override;
    function GetEntity(const AIndex: Integer): TsgDXFEntity; override;
    procedure ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord); override;
    procedure SetEntity(const AIndex: Integer;
      const AEntity: TsgDXFEntity); override;
    procedure SetJustify(const Value: Byte);
    procedure SetPoint(AValue: TFPoint); override;
    procedure SetScaleFactor(const Value: Double);
    procedure SetStyle(const Value: TsgMLineStyle);
    procedure SetFlags(const Value: Integer); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure Clear(const ADoFree: Boolean = True); override;
    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property Style: TsgMLineStyle read GetStyle write SetStyle;
    property ScaleFactor: Double read GetScaleFactor write SetScaleFactor;
    property StartPoint: TFPoint read FStartPoint write FStartPoint;
    property Justify: Byte read GetJustify write SetJustify;
    property Items[Index: Integer]: TsgMVertex read GetItem; default;
    property ItemsCount: Integer read GetItemsCount;
  end;

  TsgCADHelix = class(TsgDXFSpline)
  private
    FStart: TFPoint;
    FRadius: Double;
    FTurns: Double;
    FTurnHeight: Double;
    FClockwise: Boolean;
  protected
    function GetEntType: TsgCADEntities; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property Start: TFPoint read FStart write FStart;
    property Radius: Double read FRadius write FRadius;
    property Turns: Double read FTurns write FTurns;
    property TurnHeight: Double read FTurnHeight write FTurnHeight;
    property Clockwise: Boolean read FClockwise write FClockwise;
  end;

  TsgDXFField = class(TsgDXFOwneredItem)
  private
    FCache: TsgCADExtendedData;
    FChildFields: TList;
    FDataSet: TsgCADExtendedData;
    FEvaluatorID: string;
    FExpression: string;
    FFieldCode: string;
    FFormat2Digits: Boolean;
    FObjectIDs: TsgInt64List;
    FOverflowFieldCode: string;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    procedure GenerateFieldCode;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    property Expression: string read FExpression write FExpression;
    property Format2Digits: Boolean read FFormat2Digits write FFormat2Digits;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function EntName: string; override;
    property ChildFields: TList read FChildFields;
    property Cache: TsgCADExtendedData read FCache;
    property DataSet: TsgCADExtendedData read FDataSet;
    property EvaluatorID: string read FEvaluatorID write FEvaluatorID;
    property FieldCode: string read FFieldCode write FFieldCode;
    property ObjectIDs: TsgInt64List read FObjectIDs;
    property OverflowFieldCode: string read FOverflowFieldCode
      write FOverflowFieldCode;
  end;

  TsgDXFDictionary = class(TsgDXFTable)
  protected
    function GetValue: string; virtual;
    procedure SetValue(const AValue: string); virtual;
  public
    property Value: string read GetValue write SetValue;
  end;

  TsgDXFXRecord = class(TsgDXFOwneredItem)
  private
    FData: TsgCADExtendedData;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetExtData(const AData: TsgCADExtendedData): Boolean; override;
    procedure SetExtData(const AData: TsgCADExtendedData); override;
    property Data: TsgCADExtendedData read FData write SetExtData;
  end;

  TsgDXFDictionaryVar = class(TsgDXFDictionary)
  private
    FIntVal: Integer;
    FValue: string;
  protected
    function GetValue: string; override;
    procedure SetValue(const AValue: string); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function EntName: string; override;
    property IntVal: Integer read FIntVal write FIntVal;
  end;

  TsgCADWipeoutVariables = class(TsgDXFOwneredItem)
  private
    FDisplayImageFrame: Boolean;
  public
    constructor Create; override;
    property DisplayImageFrame: Boolean read FDisplayImageFrame
      write FDisplayImageFrame;
  end;

  TsgCADRasterVariables = class(TsgCADWipeoutVariables)
  private
    FImageDisplayQuality: Boolean;
    FUnitsForInsertingImages: Integer;
  public
    constructor Create; override;
    property ImageDisplayQuality: Boolean read FImageDisplayQuality
      write FImageDisplayQuality;
    property UnitsForInsertingImages: Integer read FUnitsForInsertingImages
      write FUnitsForInsertingImages;
  end;

{$IFDEF DATA_LINK}

  TsgCADDataLink = class(TsgDXFOwneredItem)
  private
    FFileName: string;
  public
    constructor Create; override;
    property FileName: string read FFileName write FFileName;
  end;
{$ENDIF}

  TsgDXFFieldList = class(TsgDXFDictionary)
  protected
    procedure ListNotify(Ptr: Pointer; Action: TListNotification); override;
  end;

  TsgDXFDimension = class(TsgDXFInsert)
  private
    FArcDefPoint: TFPoint;
    FAssociated: TsgDXFEntity;
    FDefPoint: TFPoint;
    FDimStyleItem: TsgTableItem;
    FFlags: Integer;
    FLinDefPoint1: TFPoint;
    FLinDefPoint2: TFPoint;
    FMiddlePoint: TFPoint;
    FRadDefPoint: TFPoint;
    FTextOverride: string;
    FTextRotation: Double;
    FPropertiesItem: TsgTableItem;
    function GetActualDimStyle: TsgDXFDimensionStyle;
    function GetInternalBlockName(const AConverter: TsgDXFConverter): string;
    function GetProperties: TsgDXFDimensionStyle;
    function GetDimType: TsgDimensionType;
  protected
    function BeginExtData(const AData: TsgCADExtendedData): Boolean; override;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    procedure CreateBlock(const AConverter: TsgDXFConverter);
    procedure EndExtData(const AData: TsgCADExtendedData); override;
    function GetArcDefPoint: TFPoint;
    function GetArrowSize: TsgFloat;
    function GetArrowType: Byte;
    function GetArrowType1: Byte;
    function GetArrowType2: Byte;
    function GetArrowTypeL: Byte;
    function GetBlockOffset: TFPoint; override;
    procedure GenerateBlock(const AConverter: TsgDXFConverter);
    function GetDefPoint: TFPoint;
    function GetDimStyleInternal: Pointer; override;
    function GetTextStyleInternal: Pointer; override;
    function GetDimArrowType1: TsgDimArrowType;
    function GetDimArrowType2: TsgDimArrowType;
    function GetDIMBLK: TsgDXFBlock;
    function GetDimBlk1: TsgDXFBlock;
    function GetDimBlk2: TsgDXFBlock;
    function GetDIMLDRBLK: TsgDXFBlock;
    function GetDIMBLKT: TsgDimArrowType;
    function GetDIMBLK1T: TsgDimArrowType;
    function GetDIMBLK2T: TsgDimArrowType;
    function GetDIMLDRBLKT: TsgDimArrowType;
    function GetDIMSAH: Boolean;
    function GetDIMSD1: Boolean;
    function GetDIMSD2: Boolean;
    function GetDIMSE1: Boolean;
    function GetDIMSE2: Boolean;
    function GetDIMTIH: Boolean;
    function GetDIMTOH: Boolean;
    function GetDIMCLRD: TsgColorCAD;
    function GetDIMCLRE: TsgColorCAD;
    function GetDIMCLRT: TsgColorCAD;
    function GetDIMLWD: TsgFloat;
    function GetDIMLWE: TsgFloat;
    function GetExtLineExt: TsgFloat;
    function GetExtLineOffset: TsgFloat;
    function GetStyle: TsgDXFDimensionStyle;
    function GetEntType: TsgCADEntities; override;
    function GetForceText: Integer;
    function GetLinDefPoint1: TFPoint;
    function GetLinDefPoint2: TFPoint;
    function GetMeasurementsScale: Double;
    function GetPrecision: Integer;
    function GetRadDefPoint: TFPoint;
    function GetTextAlign: Integer;
    function GetTextHeight: TsgFloat;
    function GetTextHeightReal: TsgFloat;
    function GetTextOffset: TsgFloat;
    function GetTextOverride: string;
    function GetTextPosVert: TsgDimTextPosVert;
    function GetTextRotation: Double;
    function GetTextStyle: TsgDXFStyle;
    function GetFlags: Integer; override;
    function IsInternalDimension: Boolean;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    procedure ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord); override;
    procedure SetArcDefPoint(const Value: TFPoint);
    procedure SetArrowSize(const Value: TsgFloat);
    procedure SetArrowType(const Value: Byte);
    procedure SetArrowType1(const Value: Byte);
    procedure SetArrowType2(const Value: Byte);
    procedure SetArrowTypeL(const Value: Byte);
    procedure SetConverter(const AConverter: TsgDXFConverter); override;
    procedure SetDefPoint(const Value: TFPoint);
    procedure SetDimArrowType1(const Value: TsgDimArrowType);
    procedure SetDimArrowType2(const Value: TsgDimArrowType);
    procedure SetDIMBLK(const Value: TsgDXFBlock);
    procedure SetDimBlk1(const Value: TsgDXFBlock);
    procedure SetDimBlk2(const Value: TsgDXFBlock);
    procedure SetDIMLDRBLK(const Value: TsgDXFBlock);
    procedure SetDIMBLKT(const Value: TsgDimArrowType);
    procedure SetDIMBLK1T(const Value: TsgDimArrowType);
    procedure SetDIMBLK2T(const Value: TsgDimArrowType);
    procedure SetDIMLDRBLKT(const Value: TsgDimArrowType);
    procedure SetDIMSAH(const Value: Boolean);
    procedure SetDIMSD1(const Value: Boolean);
    procedure SetDIMSD2(const Value: Boolean);
    procedure SetDIMSE1(const Value: Boolean);
    procedure SetDIMSE2(const Value: Boolean);
    procedure SetDIMTIH(const Value: Boolean);
    procedure SetDIMTOH(const Value: Boolean);
    procedure SetDIMCLRD(const Value: TsgColorCAD);
    procedure SetDIMCLRE(const Value: TsgColorCAD);
    procedure SetDIMCLRT(const Value: TsgColorCAD);
    procedure SetDIMLWD(const Value: TsgFloat);
    procedure SetDIMLWE(const Value: TsgFloat);
    procedure SetExtLineExt(const Value: TsgFloat);
    procedure SetExtLineOffset(const Value: TsgFloat);
    procedure SetForceText(const Value: Integer);
    procedure SetLinDefPoint1(const Value: TFPoint);
    procedure SetLinDefPoint2(const Value: TFPoint);
    procedure SetMeasurementsScale(const Value: Double);
    procedure SetPrecision(const Value: Integer);
    procedure SetRadDefPoint(const Value: TFPoint);
    procedure SetStyle(ADimStyle: TsgDXFDimensionStyle);
    procedure SetStyleInternal(const AValue: TsgDXFDimensionStyle);
    procedure SetTextAlign(const Value: Integer);
    procedure SetTextHeight(const Value: TsgFloat);
    procedure SetTextOffset(const Value: TsgFloat);
    procedure SetTextOverride(const Value: string);
    procedure SetTextPosVert(const Value: TsgDimTextPosVert);
    procedure SetTextRotation(const Value: Double);
    procedure SetTextStyle(const Value: TsgDXFStyle);
    procedure SetFlags(const Value: Integer); override;
    procedure CopyProperties(const ADim: TsgDXFDimension);
    function UseTextStyleFixedHeight: Boolean;

    function ToXMLGeoData(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;

    property ActualDimStyle: TsgDXFDimensionStyle read GetActualDimStyle;
    property Properties: TsgDXFDimensionStyle read GetProperties;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetExtData(const AData: TsgCADExtendedData): Boolean; override;
    property ArcDefPoint: TFPoint read GetArcDefPoint write SetArcDefPoint;
    property ArrowSize: TsgFloat read GetArrowSize write SetArrowSize;
    property ArrowType: Byte read GetArrowType write SetArrowType;
    property ArrowTypeL: Byte read GetArrowTypeL write SetArrowTypeL;
    property ArrowType1: Byte read GetArrowType1 write SetArrowType1;
    property ArrowType2: Byte read GetArrowType2 write SetArrowType2;

    property DimArrowType1: TsgDimArrowType read GetDimArrowType1
      write SetDimArrowType1;
    property DimArrowType2: TsgDimArrowType read GetDimArrowType2
      write SetDimArrowType2;

    property DimType: TsgDimensionType read GetDimType;

    property Associated: TsgDXFEntity read FAssociated write FAssociated;
    property DefPoint: TFPoint read GetDefPoint write SetDefPoint;
    property DIMLDRBLK: TsgDXFBlock read GetDIMLDRBLK write SetDIMLDRBLK;
    property DIMLDRBLKT: TsgDimArrowType read GetDIMLDRBLKT write SetDIMLDRBLKT;
    property DIMBLK: TsgDXFBlock read GetDIMBLK write SetDIMBLK;
    property DIMBLKT: TsgDimArrowType read GetDIMBLKT write SetDIMBLKT;
    property DimBlk1: TsgDXFBlock read GetDimBlk1 write SetDimBlk1;
    property DIMBLK1T: TsgDimArrowType read GetDIMBLK1T write SetDIMBLK1T;
    property DimBlk2: TsgDXFBlock read GetDimBlk2 write SetDimBlk2;
    property DIMBLK2T: TsgDimArrowType read GetDIMBLK2T write SetDIMBLK2T;
    property DIMSAH: Boolean read GetDIMSAH write SetDIMSAH;
    property DIMSD1: Boolean read GetDIMSD1 write SetDIMSD1;
    property DIMSD2: Boolean read GetDIMSD2 write SetDIMSD2;
    property DIMSE1: Boolean read GetDIMSE1 write SetDIMSE1;
    property DIMSE2: Boolean read GetDIMSE2 write SetDIMSE2;
    property DIMTIH: Boolean read GetDIMTIH write SetDIMTIH;
    property DIMTOH: Boolean read GetDIMTOH write SetDIMTOH;
    property DIMCLRD: TsgColorCAD read GetDIMCLRD write SetDIMCLRD;
    property DIMCLRE: TsgColorCAD read GetDIMCLRE write SetDIMCLRE;
    property DIMCLRT: TsgColorCAD read GetDIMCLRT write SetDIMCLRT;
    property DIMLWD: TsgFloat read GetDIMLWD write SetDIMLWD;
    property DIMLWE: TsgFloat read GetDIMLWE write SetDIMLWE;
    property ExtLineExt: TsgFloat read GetExtLineExt write SetExtLineExt;
    property ExtLineOffset: TsgFloat read GetExtLineOffset
      write SetExtLineOffset;
    property ForceText: Integer read GetForceText write SetForceText;
    property LinDefPoint1: TFPoint read GetLinDefPoint1 write SetLinDefPoint1;
    property LinDefPoint2: TFPoint read GetLinDefPoint2 write SetLinDefPoint2;
    property MeasurementsScale: Double read GetMeasurementsScale
      write SetMeasurementsScale;
    property MiddlePoint: TFPoint read FMiddlePoint write FMiddlePoint;
    property Style: TsgDXFDimensionStyle read GetStyle write SetStyle;
    property Precision: Integer read GetPrecision write SetPrecision;
    property RadDefPoint: TFPoint read GetRadDefPoint write SetRadDefPoint;
    property TextAlign: Integer read GetTextAlign write SetTextAlign;
    property TextHeight: TsgFloat read GetTextHeight write SetTextHeight;
    property TextOffset: TsgFloat read GetTextOffset write SetTextOffset;
    property TextOverride: string read GetTextOverride write SetTextOverride;
    property TextPosVert: TsgDimTextPosVert read GetTextPosVert
      write SetTextPosVert;
    property TextRotation: Double read GetTextRotation write SetTextRotation;
    property TextStyle: TsgDXFStyle read GetTextStyle write SetTextStyle;
  end;

  TsgDXFDimensionStyle = class(TsgDXFPenTableItem)
  private
    FBlks: array [vnDIMBLK .. vnDIMLRBLK] of TsgDXFBlock;
    FTextStyleItem: TsgTableItem;
    function GetASZ: TsgFloat;
    function GetArrowType: Byte; // deprecated;
    function GetArrowType1: Byte; // deprecated;
    function GetArrowType2: Byte; // deprecated;
    function GetArrowTypeL: Byte; // deprecated;
    function GetArrowTypeByBlock(const ABlock: TsgDXFBlock): TsgDimArrowType;
    function GetDimArrowType1: TsgDimArrowType;
    function GetDimArrowType2: TsgDimArrowType;
    function GetDIMBLKT: TsgDimArrowType;
    function GetDIMBLK1T: TsgDimArrowType;
    function GetDIMBLK2T: TsgDimArrowType;
    function GetDIMLDRBLKT: TsgDimArrowType;
    function GetDIMBLK: TsgDXFBlock;
    function GetDimBlk1: TsgDXFBlock;
    function GetDimBlk2: TsgDXFBlock;
    function GetDIMLDRBLK: TsgDXFBlock;
    function GetDIMSD1: Boolean;
    function GetDIMSD2: Boolean;
    function GetDIMSAH: Boolean;
    function GetDIMSE1: Boolean;
    function GetDIMSE2: Boolean;
    function GetDIMTIH: Boolean;
    function GetDIMTOH: Boolean;
    function GetCLRD: TsgColorCAD;
    function GetCLRE: TsgColorCAD;
    function GetCLRT: TsgColorCAD;
    function GetDEC: Integer;
    function GetEXE: TsgFloat;
    function GetEXO: TsgFloat;
    function GetLFAC: Double;
    function GetLWD: TsgFloat;
    function GetLWE: TsgFloat;
    function GetScale: Double;
    function GetCEN: TsgFloat;
    function GetTextAlign: Integer;
    function GetTXT: TsgFloat;
    function GetGAP: TsgFloat;
    function GetTAD: TsgDimTextPosVert;
    function GetTXSTY: TsgDXFStyle;
    function GetTIX: Integer;
    procedure SetArrows(AArrows: TsgArrows);
    procedure SetASZ(const Value: TsgFloat);
    procedure SetArrowTypeEx(const AValue: TsgDimArrowType;
      const APropName: TsgDimNameVal); overload;
    procedure SetArrowTypeEx(const AValue: string;
      const APropName: TsgDimNameVal;
      AValueType: TsgDimArrowType = datUndefined); overload;
    procedure SetArrowType(const Value: Byte); // deprecated;
    procedure SetArrowType1(const Value: Byte); // deprecated;
    procedure SetArrowType2(const Value: Byte); // deprecated;
    procedure SetArrowTypeL(const Value: Byte); // deprecated;
    procedure SetBlocksInternal(const AType: TsgDimNameVal;
      const AValue: TsgDXFBlock);
    procedure SetDimArrowType1(const Value: TsgDimArrowType);
    procedure SetDimArrowType2(const Value: TsgDimArrowType);
    procedure SetDIMBLKT(const Value: TsgDimArrowType);
    procedure SetDIMBLK1T(const Value: TsgDimArrowType);
    procedure SetDIMBLK2T(const Value: TsgDimArrowType);
    procedure SetDIMLDRBLKT(const Value: TsgDimArrowType);
    procedure SetDIMBLK(const Value: TsgDXFBlock);
    procedure SetDimBlk1(const Value: TsgDXFBlock);
    procedure SetDimBlk2(const Value: TsgDXFBlock);
    procedure SetDIMLDRBLK(const Value: TsgDXFBlock);
    procedure SetDIMSD1(const Value: Boolean);
    procedure SetDIMSD2(const Value: Boolean);
    procedure SetDIMSAH(const Value: Boolean);
    procedure SetDIMSE1(const Value: Boolean);
    procedure SetDIMSE2(const Value: Boolean);
    procedure SetDIMTIH(const Value: Boolean);
    procedure SetDIMTOH(const Value: Boolean);
    procedure SetCLRD(const Value: TsgColorCAD);
    procedure SetCLRE(const Value: TsgColorCAD);
    procedure SetCLRT(const Value: TsgColorCAD);
    procedure SetDEC(const Value: Integer);
    procedure SetEXE(const Value: TsgFloat);
    procedure SetEXO(const Value: TsgFloat);
    procedure SetLFAC(const Value: Double);
    procedure SetLWD(const Value: TsgFloat);
    procedure SetLWE(const Value: TsgFloat);
    procedure SetScale(const Value: Double);
    procedure SetCEN(const Value: TsgFloat);
    procedure SetTextAlign(const Value: Integer);
    procedure SetTXT(const Value: TsgFloat);
    procedure SetGAP(const Value: TsgFloat);
    procedure SetTAD(const Value: TsgDimTextPosVert);
    procedure SetTXSTY(const Value: TsgDXFStyle);
    procedure SetTIX(const Value: Integer);
  protected
    FDimProps: TsgDimStyle;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    function GetBlocks(const AType: TsgDimNameVal): TsgDXFBlock;
    function GetActualStyle(const ANameValue: TsgDimNameVal;
      const ASetValue: Boolean = False): TsgDXFDimensionStyle; virtual;
    function GetTextHeightReal(var AHeight: Double): Boolean;
    function GetOwnerStyle: TsgDXFDimensionStyle; virtual;
    function GetPropertiesInit: TsgDimNameVals; virtual;
    procedure RemoveReferenceNotification(const ARefObj: TsgDXFEntity);
      override;
    procedure SetBlocks(const AType: TsgDimNameVal;
      const AValue: TsgDXFBlock); overload;
    procedure SetBlocks(const AType: TsgDimNameVal; const AValue: string;
      AConverter: TsgDXFConverter); overload;
    procedure SetOwnerStyle(const AValue: TsgDXFDimensionStyle); virtual;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function ToXMLAsProperties(const ANode: TsgNode;
      const AMode: TsgXMLModes): Integer;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    function FromXMLAsProperties(const ANode: TsgNodeSample;
      const AResult: IsgResultNode = nil): Integer;
    procedure UpdateDimProps(ADimProps: TsgDimStyle);
    property TextAlign: Integer read GetTextAlign write SetTextAlign;
    property PropertiesInit: TsgDimNameVals read GetPropertiesInit;
    property OwnerStyle: TsgDXFDimensionStyle read GetOwnerStyle
      write SetOwnerStyle;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    procedure InitProps(AHeader: PsgHeadVarStruct);
    function ReplaceBlock(const ABlockPrev, ABlockNew: TsgDXFBlock): Boolean;
    property ArrowSize: TsgFloat read GetASZ write SetASZ; // used DIMASZ
    property ArrowType: Byte read GetArrowType write SetArrowType;
    // used DIMBLKT
    property ArrowType1: Byte read GetArrowType1 write SetArrowType1;
    // used DIMBLK1T
    property ArrowType2: Byte read GetArrowType2 write SetArrowType2;
    // used DIMBLK2T
    property ArrowTypeL: Byte read GetArrowTypeL write SetArrowTypeL;
    // used DIMLDRBLKT

    property DimArrowType1: TsgDimArrowType read GetDimArrowType1
      write SetDimArrowType1;
    property DimArrowType2: TsgDimArrowType read GetDimArrowType2
      write SetDimArrowType2;

    property ExtLineExt: TsgFloat read GetEXE write SetEXE; // used DIMEXE
    property ExtLineOffset: TsgFloat read GetEXO write SetEXO; // used DIMEXO
    property Scale: Double read GetScale write SetScale; // used  DIMSCALE
    property TextOffset: TsgFloat read GetGAP write SetGAP; // used DIMGAP
    property TextHeight: TsgFloat read GetTXT write SetTXT; // used DIMTXT
    property TextPosVert: TsgDimTextPosVert read GetTAD write SetTAD;
    // used DIMTAD
    property TextStyle: TsgDXFStyle read GetTXSTY write SetTXSTY;
    // used DIMTXSTY
    property SizeCenterMark: TsgFloat read GetCEN write SetCEN; // used DIMCEN

    property DIMASZ: TsgFloat read GetASZ write SetASZ;
    property DIMCEN: TsgFloat read GetCEN write SetCEN;
    property DIMCLRD: TsgColorCAD read GetCLRD write SetCLRD;
    property DIMCLRE: TsgColorCAD read GetCLRE write SetCLRE;
    property DIMCLRT: TsgColorCAD read GetCLRT write SetCLRT;
    property DIMLDRBLK: TsgDXFBlock read GetDIMLDRBLK write SetDIMLDRBLK;
    property DIMLDRBLKT: TsgDimArrowType read GetDIMLDRBLKT write SetDIMLDRBLKT;
    property DIMBLK: TsgDXFBlock read GetDIMBLK write SetDIMBLK;
    property DIMBLKT: TsgDimArrowType read GetDIMBLKT write SetDIMBLKT;
    property DimBlk1: TsgDXFBlock read GetDimBlk1 write SetDimBlk1;
    property DIMBLK1T: TsgDimArrowType read GetDIMBLK1T write SetDIMBLK1T;
    property DimBlk2: TsgDXFBlock read GetDimBlk2 write SetDimBlk2;
    property DIMBLK2T: TsgDimArrowType read GetDIMBLK2T write SetDIMBLK2T;
    property DIMDEC: Integer read GetDEC write SetDEC;
    property DIMEXE: TsgFloat read GetEXE write SetEXE;
    property DIMEXO: TsgFloat read GetEXO write SetEXO;
    property DimLFac: Double read GetLFAC write SetLFAC;
    property DIMLWD: TsgFloat read GetLWD write SetLWD;
    property DIMLWE: TsgFloat read GetLWE write SetLWE;
    property DIMGAP: TsgFloat read GetGAP write SetGAP;
    property DIMTAD: TsgDimTextPosVert read GetTAD write SetTAD;
    property DIMTIX: Integer read GetTIX write SetTIX;
    property DIMTIH: Boolean read GetDIMTIH write SetDIMTIH;
    property DIMTOH: Boolean read GetDIMTOH write SetDIMTOH;
    property DIMTXT: TsgFloat read GetTXT write SetTXT;
    property DIMTXSTY: TsgDXFStyle read GetTXSTY write SetTXSTY;
    property DIMSAH: Boolean read GetDIMSAH write SetDIMSAH;
    property DimScale: Double read GetScale write SetScale;
    property DIMSD1: Boolean read GetDIMSD1 write SetDIMSD1;
    property DIMSD2: Boolean read GetDIMSD2 write SetDIMSD2;
    property DIMSE1: Boolean read GetDIMSE1 write SetDIMSE1;
    property DIMSE2: Boolean read GetDIMSE2 write SetDIMSE2;
  end;

  TsgDXFDimensionProperties = class(TsgDXFDimensionStyle)
  private
    FOwnerStyleItem: TsgTableItem;
    FPropertiesInit: TsgDimNameVals;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetConverter: TsgDXFConverter; override;
    function GetActualStyle(const ANameValue: TsgDimNameVal;
      const ASetValue: Boolean = False): TsgDXFDimensionStyle; override;
    function GetOwnerStyle: TsgDXFDimensionStyle; override;
    function GetPropertiesInit: TsgDimNameVals; override;
    procedure SetOwnerStyle(const AValue: TsgDXFDimensionStyle); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetExtData(const AData: TsgCADExtendedData): Boolean; override;
  end;

  TsgDXFLeader = class(TsgDXFSpline)
  private
    FArrowhead: Boolean;
    FArrowPoint: TFPoint;
    FDimStyleItem: TsgTableItem;
    FInsert: TsgDXFInsert;
    FIsSpline: Boolean;
    FPropertiesItem: TsgTableItem;
    FTextPoint: TFPoint;
    function GetActualDimStyle: TsgDXFDimensionStyle;
    function GetDIMBLK: TsgDXFBlock;
    function GetDimBlk1: TsgDXFBlock;
    function GetDimBlk2: TsgDXFBlock;
    function GetDIMLDRBLK: TsgDXFBlock;
    function GetProperties: TsgDXFDimensionStyle;
    function GetTextStyle: TsgDXFStyle;
    procedure LoadInsert(AConverter: TsgDXFConverter; NextControl: Integer;
      const ALineAngle: Double);
    procedure SetDIMBLK(const AValue: TsgDXFBlock);
    procedure SetDimBlk1(const AValue: TsgDXFBlock);
    procedure SetDimBlk2(const AValue: TsgDXFBlock);
    procedure SetDIMLDRBLK(const AValue: TsgDXFBlock);
    procedure SetTextStyle(const AValue: TsgDXFStyle);
  protected
    function BeginExtData(const AData: TsgCADExtendedData): Boolean; override;
    procedure DoAdditionalLine(const AHookLine, AHookLineDirectional: Integer;
      const AHookLineVector: TFPoint; const ATAD: Integer;
      const AGAP, AWidth: Double);
    procedure EndExtData(const AData: TsgCADExtendedData); override;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetArrowSize: Double;
    function GetArrowScale: Double;
    function GetArrowType: Byte;
    function GetDimArrowType: TsgDimArrowType;
    function GetEntType: TsgCADEntities; override;
    function GetDimStyle: TsgDXFDimensionStyle;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    procedure SetArrowSize(AValue: Double);
    procedure SetArrowScale(const AValue: Double);
    procedure SetArrowType(const AValue: Byte);
    procedure SetDimArrowType(const AValue: TsgDimArrowType);
    procedure SetColorCAD(const Value: TsgColorCAD); override;
    procedure SetConverter(const AConverter: TsgDXFConverter); override;
    procedure SetVisibility(const Value: Boolean); override;
    procedure SetDimStyle(const AValue: TsgDXFDimensionStyle);
    procedure SetDimStyleInternal(const AValue: TsgDXFDimensionStyle);
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property ActualDimStyle: TsgDXFDimensionStyle read GetActualDimStyle;
    property Properties: TsgDXFDimensionStyle read GetProperties;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetExtData(const AData: TsgCADExtendedData): Boolean; override;
    property Insert: TsgDXFInsert read FInsert;
    property IsSpline: Boolean read FIsSpline write FIsSpline;
    property Arrowhead: Boolean read FArrowhead write FArrowhead;
    property ArrowSize: Double read GetArrowSize write SetArrowSize;
    property ArrowScale: Double read GetArrowScale write SetArrowScale;
    property ArrowType: Byte read GetArrowType write SetArrowType;
    property DimArrowType: TsgDimArrowType read GetDimArrowType
      write SetDimArrowType;
    property DIMLDRBLK: TsgDXFBlock read GetDIMLDRBLK write SetDIMLDRBLK;
    property DIMBLK: TsgDXFBlock read GetDIMBLK write SetDIMBLK;
    property DimBlk1: TsgDXFBlock read GetDimBlk1 write SetDimBlk1;
    property DimBlk2: TsgDXFBlock read GetDimBlk2 write SetDimBlk2;
    property TextStyle: TsgDXFStyle read GetTextStyle write SetTextStyle;
    property DimStyle: TsgDXFDimensionStyle read GetDimStyle write SetDimStyle;
  end;

  TsgDXFText = class(TsgDXFCustomVertex)
  private
    FBox: TFRect;
    FFont: TmvExtFont;
    FHAlign: Byte;
    FInternalFlags: TsgInternalTextFlags;
    FMText: TsgDXFMText;
    FTextParse: PsgTextParse;
    FPoint1: TFPoint;
    FRotation: Single;
    FExtrusion: TFPoint;
    FStartPoint: TFPoint;
    FSHXText: string;
    FMatrix: TFMatrix;
    FSHXUnicodeText: WideString;
    FTextStyleItem: TsgTableItem;
    FText: string;
    FLineWeight: Double;
    FUnicodeText: WideString;
    FVAlign: Byte;
    FPropertiesItem: TsgTableItem;
    procedure ApplyRotation;
    function GetSHXBox(const AStr: string; const AWStr: WideString;
      CodePage: Integer; ASHXFontsList: TsgSHXFontList;
      var AFontParams: TsgFontParams): Boolean;
    function Expand(AWidth, AHeight, AHeightMax: Extended;
      const ASign: TFPoint): Boolean;
    procedure SetGeneration(const Value: Byte);
    function GetGeneration: Byte;
    function GetFontName: string;
    function GetSymbolFromMultibyte(const AConverter: TsgDXFConverter;
      const ALeft, ARight: Byte; const ANumber: Integer;
      const AUnicodeAlways: Boolean): WideChar;
    function GetSHXUnicodeText: WideString;
    function GetUnicodeText: WideString;
    function GetIsUnicodeText: Boolean;

    { internal flags methods }
    function GetInsideMText: Boolean;
    function GetIsSHXFont: Boolean;
    function GetUseDefaultFontName: Boolean;
    function GetWinFont: Boolean;
    procedure SetInsideMText(const AValue: Boolean);
    procedure SetInternalFlag(const AInternalFlag: TsgInternalTextFlag;
      const AValue: Boolean);
    procedure SetInternalTextFlags(const AValue: TsgInternalTextFlags);
    procedure SetIsSHXFont(const AValue: Boolean);
    procedure SetUseDefaultFontName(const AValue: Boolean);
    procedure SetWinFont(const AValue: Boolean);
    procedure SetStyleRef(const Value: TsgDXFStyle);
    procedure SetProperties(const Value: TsgDXFStyle);
    procedure SetScale(const Value: Double);
    function GetScale: Double;
    function GetProperties: TsgDXFStyle;
  protected
    procedure ApplyStyle(const AStyle: TsgDXFStyle);
    procedure ApplyStyleProps(const AStyle: TsgDXFStyle);
    procedure CreateTextParse;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetAnsiText(const AText: string; ACodePage: Integer)
      : sgRawByteString; virtual;
    function GetBackward: Boolean;
    function GetFFontName: string;
    function GetHeight: TsgFloat;
    function GetOblique: Single;
    function GetPoint1: TFPoint;
    function GetRotation: Single;
    function GetXScale: Single;
    function GetStyle: TsgDXFStyle;
    function GetSHXFont: string; virtual;
    function GetText: string;
    function GetTextStyleInternal: Pointer; override;
    function GetUpsideDown: Boolean;
    procedure ChangeByStyle(AStyle: TsgDXFStyle);
    procedure SetBackward(const AValue: Boolean);
    procedure SetHeight(AValue: TsgFloat);
    procedure SetOblique(Value: Single);
    procedure SetPoint1(AValue: TFPoint);
    procedure SetRotation(AValue: Single);
    procedure SetXScale(const Value: Single);
    procedure SetStyle(AStyle: TsgDXFStyle);
    procedure SetFontName(const AFontName: string);
    procedure SetSHXFont(const AFontName: string);
    procedure SetTTFFont(const AFontName: string);
    procedure SetTextValue(const Value: string);
    procedure SetUpsideDown(const Value: Boolean);
    function GetBox: TFRect; override;
    function GetEntType: TsgCADEntities; override;
    function GetExtrusion: TFPoint; override;
    function GetIsEmpty: Boolean; virtual;
    function GetLineWeight: Double; override;
    function HasSecond: Boolean;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); override;
    function IsNotSetFontName: Boolean;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    procedure SetColorCAD(const Value: TsgColorCAD); override;
    procedure SetDefaulParams(AConverter: TsgDXFConverter);
    procedure SetExtrusion(const Value: TFPoint); override;
    procedure SetLineWeight(Value: Double); override;
    procedure StyleChanged(Sender: TObject); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property UseDefaultFontName: Boolean read GetUseDefaultFontName
      write SetUseDefaultFontName;
    property InternalTextFlags: TsgInternalTextFlags read FInternalFlags
      write SetInternalTextFlags;
    property Properties: TsgDXFStyle read GetProperties write SetProperties;
    property StyleRef: TsgDXFStyle read GetStyle write SetStyleRef;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function EntName: string; override;
    function IsOnePixelOptimisationValid: Boolean; override;
    function SHXMatrix: TFMatrix;
    procedure DoNewText(const ANewText: string);
    procedure GetBase(AWidth, AHeight: Extended;
      var Base, Start: TFPoint); virtual;
    function GetMatrix: TFMatrix;
    procedure GetSHXLines(const AStr: string; const AWStr: WideString;
      CodePage: Integer; ASHXFontsList: TsgSHXFontList; AList: TList;
      var AFontParams: TsgFontParams);
    procedure GetSHXLinesEx(ASHXFontsList: TsgSHXFontList; AList: TList;
      const AMatrix: PFMatrix; const APolyPolyline: TsgIntegerList;
      const ACounts: TsgIntegerList; CodePage: Integer);
    function GetThickness: Double; override;
    procedure SetLWeight(Value: Integer); override;
    property Backward: Boolean read GetBackward;
    property Extrusion: TFPoint read GetExtrusion write SetExtrusion;
    property Font: TmvExtFont read FFont;
    property FontName: string read GetFontName;
    property Generation: Byte read GetGeneration write SetGeneration;
    property HAlign: Byte read FHAlign write FHAlign;
    property Height: TsgFloat read GetHeight write SetHeight;
    property InsideMText: Boolean read GetInsideMText write SetInsideMText;
    property IsEmpty: Boolean read GetIsEmpty;
    property IsUnicodeText: Boolean read GetIsUnicodeText;
    property IsSHXFont: Boolean read GetIsSHXFont write SetIsSHXFont;
    property MText: TsgDXFMText read FMText;
    property ObliqueAngle: Single read GetOblique write SetOblique;
    property Point1: TFPoint read GetPoint1 write SetPoint1;
    property Rotation: Single read FRotation write FRotation;
    property Scale: Double read GetScale write SetScale;
    property SHXText: string read FSHXText;
    property SHXUnicodeText: WideString read GetSHXUnicodeText;
    property SHXFont: string read GetSHXFont;
    property StartPoint: TFPoint read FStartPoint;
    property Style: TsgDXFStyle read GetStyle write SetStyle;
    property Text: string read FText write SetTextValue;
    property UnicodeText: WideString read GetUnicodeText;
    property UpsideDown: Boolean read GetUpsideDown;
    property VAlign: Byte read FVAlign write FVAlign;
    property WinFont: Boolean read GetWinFont write SetWinFont;
    property XScale: Single read GetXScale write SetXScale;
  end;

  TsgDXFShape = class(TsgDXFText)
  private
    FShapeName: string;
    FShapeNumber: Word;
  protected
    function GetAnsiText(const AText: string; ACodePage: Integer)
      : sgRawByteString; override;
    function GetEntType: TsgCADEntities; override;
    function GetIsEmpty: Boolean; override;
    function GetSHXFont: string; override;
    function GetShapeName: string;
    function GetShapeNumber: Word;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure SetShapeName(const Value: string);
    procedure SetShapeNumber(const Value: Word);
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property ShapeName: string read GetShapeName write SetShapeName;
    property ShapeNumber: Word read GetShapeNumber write SetShapeNumber;
  end;

  TsgDXFMText = class(TsgDXFInsert)
  private
    FAlign: Byte;
    FHeight: TsgFloat;
    FHyphenation: Boolean;
    FLineSpacingFactor: Single;
    FLineSpacingStyle: Byte;
    FPoint1: TFPoint;
    FRectWidth: Single;
    FTextStyleItem: TsgTableItem;
    FText: string;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetAlign: Byte;
    function GetEntType: TsgCADEntities; override;
    function GetHeight: TsgFloat;
    function GetLineSpacingFactor: Single;
    function GetLineSpacingStyle: Byte;
    function GetRectWidth: Single;
    function GetStyle: TsgDXFStyle;
    function GetText: string;
    function GetTextStyleInternal: Pointer; override;
    function HasSecond: Boolean;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    function Parsing(const AConverter: TsgDXFConverter; AList: TList;
      const AColor: TsgColorCAD; ASize: Double): Boolean; virtual;
    procedure ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord); override;
    procedure SetAlign(const Value: Byte);
    procedure SetAngle(const Value: Single); override;
    procedure SetHeight(AValue: TsgFloat);
    procedure SetHyphenation(const AValue: Boolean);
    procedure SetLineSpacingFactor(const Value: Single);
    procedure SetLineSpacingStyle(const Value: Byte);
    procedure SetRectWidth(const Value: Single);
    procedure SetStyle(AValue: TsgDXFStyle);
    procedure SetTextValue(AValue: string);
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function EntName: string; override;
    function GetThickness: Double; override;
    procedure SetLWeight(Value: Integer); override;
    property Align: Byte read GetAlign write SetAlign;
    property Height: TsgFloat read FHeight write FHeight;
    property Hyphenation: Boolean read FHyphenation write SetHyphenation;
    property LineSpacingFactor: Single read GetLineSpacingFactor
      write SetLineSpacingFactor;
    property LineSpacingStyle: Byte read GetLineSpacingStyle
      write SetLineSpacingStyle;
    property Point1: TFPoint read FPoint1 write FPoint1;
    property RectHeight: Single read GetLineSpacingFactor
      write SetLineSpacingFactor;
    property RectWidth: Single read GetRectWidth write SetRectWidth;
    property Style: TsgDXFStyle read GetStyle write SetStyle;
    property Text: string read FText write FText;
  end;

  TsgDXFTolerance = class(TsgDXFMText)
  private
    FDimlineColor: TsgColorCAD;
    FDimScaleOverall: Single;
    FDimStyleItem: TsgTableItem;
    FGAP: PDouble;
  protected
    function BeginExtData(const AData: TsgCADExtendedData): Boolean; override;
    procedure EndExtData(const AData: TsgCADExtendedData); override;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetDimlineColor: TsgColorCAD;
    function GetDimScaleOverall: Single;
    function GetDimStyle: TsgDXFDimensionStyle;
    function GetEntType: TsgCADEntities; override;
    function GetGAP: Double;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    function Parsing(const AConverter: TsgDXFConverter; AList: TList;
      const AColor: TsgColorCAD; ASize: Double): Boolean; override;
    procedure SetDimlineColor(const Value: TsgColorCAD);
    procedure SetDimScaleOverall(const Value: Single);
    procedure SetDimStyle(const Value: TsgDXFDimensionStyle);
    procedure SetGAP(const Value: Double);
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetExtData(const AData: TsgCADExtendedData): Boolean; override;
    property DimlineColor: TsgColorCAD read GetDimlineColor
      write SetDimlineColor;
    property DimScaleOverall: Single read GetDimScaleOverall
      write SetDimScaleOverall;
    property DimStyle: TsgDXFDimensionStyle read GetDimStyle write SetDimStyle;
    property GAP: Double read GetGAP write SetGAP;
  end;

  TsgDXFOle2Frame = class(TsgDXFCustomVertex)
  private
    FBinaryData: AnsiString;
    FOleObject: IOleObject;
    FLockBytes: ILockBytes;
    FStorage: IStorage;
    FPoint1: TFPoint;
    FOLEObjectType: Byte;
    FAspect: Byte;
    FTileModeDescriptor: Integer;
    procedure DestroyOleObject;
    function GetFileName: string;
    function GetIsLink: Boolean;
  protected
    procedure ClearReferences; override;
    function GetEntType: TsgCADEntities; override;
    function GetBox: TFRect; override;
    function GetPoint1: TFPoint;
    function GetPosition: TFPoint;
    function GetSize: TFPoint;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure SetPoint1(const Value: TFPoint);
    procedure SetPosition(const APoint: TFPoint);
    procedure SetSize(const APoint: TFPoint);
    procedure ConvertOleToBitmap(const AWidth, AHeight: Double;
      ADrawingRect: TRect; const ABitmap: TBitmap);
    property FileName: string read GetFileName;
    property IsLink: Boolean read GetIsLink;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property OleObject: IOleObject read FOleObject;
    property OLEObjectType: Byte read FOLEObjectType write FOLEObjectType;
    property Aspect: Byte read FAspect write FAspect;
    property Point1: TFPoint read GetPoint1 write SetPoint1;
    property BinaryData: AnsiString read FBinaryData write FBinaryData;
    property TileModeDescriptor: Integer read FTileModeDescriptor
      write FTileModeDescriptor;
  end;

  TsgDXFAttdef = class(TsgDXFText)
  private
    FTagItem: TsgNamedItem;
    FHasChanging: Boolean;
    FValue: string;
    FFlags: Integer;
    FLockPosition: Boolean;
  protected
    procedure FreeReferences; override;
    function GetConstant: Boolean;
    function GetEntType: TsgCADEntities; override;
    function GetNotAppear: Boolean;
    function GetOwner: TsgDXFEntity; override;
    function GetTag: string;
    function GetValue: string;
    function GetFlags: Integer; override;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); override;
    procedure SetConstant(const Value: Boolean);
    procedure SetNotAppear(const Value: Boolean);
    procedure SetOwner(const Value: TsgDXFEntity); override;
    procedure SetTag(const ATag: string); virtual;
    procedure SetValue(const AValue: string); virtual;
    procedure SetFlags(const Value: Integer); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function EntName: string; override;
    function GetStrValue: string; override;
    function SetStrValue(S: string): Boolean; override;
    property Constant: Boolean read GetConstant write SetConstant;
    property Tag: string read GetTag write SetTag;
    property Value: string read GetValue write SetValue;
    property LockPosition: Boolean read FLockPosition write FLockPosition;
    property NotAppear: Boolean read GetNotAppear write SetNotAppear;
  end;

  TsgDXFAttrib = class(TsgDXFAttdef)
  protected
    function GetEntType: TsgCADEntities; override;
    procedure SetTag(const ATag: string); override;
    procedure SetValue(const AValue: string); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    function SetStrValue(S: string): Boolean; override;
  end;

  TsgView = class(TsgDXFEntity) // for internal using
  private
    FInternalFlags: Integer;
    FMatrix: TFMatrix;
    FStackView: TsgIntegerList;
    function GetView: TRect;
    procedure SetMatrix(const Value: TFMatrix);
    procedure SetView(const Value: TRect);
  protected
    procedure FreeReferences; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    procedure Clear(const ADoFree: Boolean = True); override;
    procedure ClearView;
    function HasDrawMatrix: Boolean;
    function HasView: Boolean;
    function HasBaseView: Boolean;
    function PopView: TRect;
    procedure PushView(const ARect: TRect);
    property DrawMatrix: TFMatrix read FMatrix write SetMatrix;
    property ActiveView: TRect read GetView write SetView;
  end;

  TsgDXFViewport = class(TsgDXFPenEntity)
  private
    FBackClipPlane: Single;
    FBox: TFRect;
    FClippingBoundary: TsgDXFEntity;
    FClippingBoundaryHandle: UInt64;
    FFlags: Integer;
    FFrontClipPlane: Single;
    FFrozenLayers: TsgInt64List;
    FMatrix: TFMatrix;
    FMSpaceCenter: TFPoint;
    FMSpaceHeight: Double;
    FOrdIndex: Integer;
    FOwnerItem: TsgOwneredItem;
    FPSpaceCenter: TFPoint;
    FPSpaceHeight: Double;
    FPSpaceWidth: Double;
    FRect: TFRect;
    FStatusField: Integer;
    FThisID: Integer;
    FViewDirection: TFPoint;
    FViewTarget: TFPoint;
    FViewTwistAngle: Single;
    FXDataAppName: string;
    FVisibleBoundary: Boolean;
    FActive: Boolean;
    function IsOwnerModel: Boolean;
  protected
    function BeginExtData(const AData: TsgCADExtendedData): Boolean; override;
    function CanDraw: Boolean; override;
    function GetBackClipPlane: Single;
    function GetBox: TFRect; override;
    function CalcMatrix: TFMatrix;
    procedure EndExtData(const AData: TsgCADExtendedData); override;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetClipBoundary(AConverter: TsgDXFConverter): TsgDXFEntity;
    function GetDrawModel: Boolean;
    function GetEntType: TsgCADEntities; override;
    function GetFrontClipPlane: Single;
    function GetMSpaceCenter: TFPoint;
    function GetOwner: TsgDXFEntity; override;
    function GetPSpaceCenter: TFPoint;
    function GetPSpaceHeight: Double;
    function GetPSpaceWidth: Double;
    function GetScale: Double;
    function GetTurnsOff: Boolean;
    function GetViewDirection: TFPoint;
    function GetViewTarget: TFPoint;
    function GetViewTwistAngle: Single;
    function GetVisibleBoundary: Boolean;
    function GetFlags: Integer; override;
    procedure SetBackClipPlane(const Value: Single);
    procedure SetFrontClipPlane(const Value: Single);
    procedure SetMSpaceCenter(const Value: TFPoint);
    procedure SetOwner(const Value: TsgDXFEntity); override;
    procedure SetPSpaceCenter(const Value: TFPoint);
    procedure SetPSpaceHeight(const Value: Double);
    procedure SetPSpaceWidth(const Value: Double);
    procedure SetScale(const Value: Double);
    procedure SetTurnsOff(const Value: Boolean);
    procedure SetViewDirection(const Value: TFPoint);
    procedure SetViewTarget(const Value: TFPoint);
    procedure SetViewTwistAngle(const Value: Single);
    procedure SetVisibleBoundary(const Value: Boolean);
    procedure SetFlags(const Value: Integer); override;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property TurnsOff: Boolean read GetTurnsOff write SetTurnsOff;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetBoundary(AConverter: TsgDXFConverter): TsgDXFEntity;
    function GetBoundariesAsPoints(AConverter: TsgDXFConverter): TList;
    function GetExtData(const AData: TsgCADExtendedData): Boolean; override;
    function IsDraw: Boolean;
    procedure Offset(const P: TFPoint);
    procedure SetBoundary(ABoundary: TsgDXFEntity);
    property BackClipPlane: Single read GetBackClipPlane write SetBackClipPlane;
    property ClippingBoundaryHandle: UInt64 read FClippingBoundaryHandle
      write FClippingBoundaryHandle;
    property FrontClipPlane: Single read GetFrontClipPlane
      write SetFrontClipPlane;
    property FrozenLayers: TsgInt64List read FFrozenLayers write FFrozenLayers;
    property MSpaceCenter: TFPoint read GetMSpaceCenter write SetMSpaceCenter;
    property MSpaceHeight: Double read FMSpaceHeight write FMSpaceHeight;
    property OrdIndex: Integer read FOrdIndex write FOrdIndex;
    property PSpaceCenter: TFPoint read GetPSpaceCenter write SetPSpaceCenter;
    property PSpaceHeight: Double read GetPSpaceHeight write SetPSpaceHeight;
    property PSpaceWidth: Double read GetPSpaceWidth write SetPSpaceWidth;
    property Rect: TFRect read FRect;
    property StatusField: Integer read FStatusField write FStatusField;
    property ThisID: Integer read FThisID write FThisID;
    property ViewDirection: TFPoint read GetViewDirection
      write SetViewDirection;
    property ViewTarget: TFPoint read GetViewTarget write SetViewTarget;
    property ViewTwistAngle: Single read GetViewTwistAngle
      write SetViewTwistAngle;
    property VisibleBoundary: Boolean read GetVisibleBoundary
      write SetVisibleBoundary;
    property XDataAppName: string read FXDataAppName write FXDataAppName;
  end;

  TsgDXFVport = class(TsgDXFPenTableItem)
  protected
    FCircleZoomPercent: Integer;
    FViewAspectRatio: TsgFloat;
    FViewCenterPoint: TFPoint;
    FViewDirection: TFPoint;
    FViewHeight: TsgFloat;
    FViewTarget: TFPoint;
    FViewTwistAngle: Double;
    FUCSOrigin: TFPoint;
    FUCSYDir: TFPoint;
    FUCSXDir: TFPoint;
    FUCSVP: Boolean;
    function GetViewDirection: TFPoint;
    function GetViewHeight: TsgFloat;
    function GetViewTwistAngle: Double;
    procedure SetViewDirection(const Value: TFPoint);
    procedure SetViewHeight(const Value: TsgFloat);
    procedure SetViewTwistAngle(const Value: Double);
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property CircleZoomPercent: Integer read FCircleZoomPercent
      write FCircleZoomPercent;
    property ViewAspectRatio: TsgFloat read FViewAspectRatio
      write FViewAspectRatio;
    property ViewCenterPoint: TFPoint read FViewCenterPoint
      write FViewCenterPoint;
    property ViewDirection: TFPoint read GetViewDirection
      write SetViewDirection;
    property ViewHeight: TsgFloat read GetViewHeight write SetViewHeight;
    property ViewTarget: TFPoint read FViewTarget write FViewTarget;
    property ViewTwistAngle: Double read GetViewTwistAngle
      write SetViewTwistAngle;
    property UCSOrigin: TFPoint read FUCSOrigin write FUCSOrigin;
    property UCSXDir: TFPoint read FUCSXDir write FUCSXDir;
    property UCSYDir: TFPoint read FUCSYDir write FUCSYDir;
    property UCSVP: Boolean read FUCSVP write FUCSVP;
  end;

  TsgDXFXref = class(TsgDXFOwneredItem)
  private
    FInvokeConverters: TsgList;
    FCADImage: TGraphic;
    FBox: TFRect;
    FPath: string;
    // FOwnerProgress: TProgressEvent;
    // procedure GraphicChange(Sender: TObject);
    // procedure ProgressEvent(Sender: TObject; Stage: TProgressStage;
    // PercentDone: Byte; RedrawNow: Boolean; const R: TRect; const Msg: string);
  protected
    function AddCADImage(const AMainConv: TsgDXFConverter;
      const AFilePath: string; ASearchPaths: TStrings = nil): Boolean;
    function CanDraw: Boolean; override;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetBox: TFRect; override;
    function GetBlock: TsgDXFBlock;
    function GetEntType: TsgCADEntities; override;
    function GetLayer: TsgDXFLayer; override;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property Block: TsgDXFBlock read GetBlock;
  public
    constructor Create; override;
    property CADImage: TGraphic read FCADImage;
    property Path: string read FPath;
  end;

  TsgDXFLayout = class(TsgDXFOwneredItem)
  private
    FBox: TFRect;
    FCADSpace: TsgCADSpace;
    FPaperSpaceBlock: TsgDXFBlock;
    FPlotSettings: TsgDXFPlotSettings;
    FRotMatrix: TFMatrix;
    FRotZAngle: Double;
    FUCSOrigin: TFPoint;
    FUCSXDir: TFPoint;
    FUCSYDir: TFPoint;
    FView: TsgView;
    procedure DoExtents(AConverter: TsgDXFConverter);
    function GetEmpty: Boolean;
    function GetIsModel: Boolean;
    function GetPaperSpaceBlock: TsgDXFBlock;
    procedure SetPaperSpaceBlock(ABlock: TsgDXFBlock);
    function GetExtMax: TFPoint;
    function GetExtMin: TFPoint;
    function GetLinMax: TFPoint;
    function GetLinMin: TFPoint;
    function GetView: TsgView;
    // function GetPlotPaperUnits: Integer; {$IFDEF SGDEL_6}deprecated{$IFDEF SGDEL_2009}'This procedure is obsolete and will be deleted in the next version. Please, use the following property - PlotSettings!'{$ENDIF};{$ENDIF}
    // procedure SetPlotPaperUnits(const Value: Integer); {$IFDEF SGDEL_6}deprecated{$IFDEF SGDEL_2009}'This procedure is obsolete and will be deleted in the next version. Please, use the following property - PlotSettings!'{$ENDIF};{$ENDIF}
    procedure SetPlotSettings(const Value: TsgDXFPlotSettings);
    function GetIndex: Integer;
    function GetBlockRecord: TsgDXFEntity;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetBox: TFRect; override;
    function GetBlockName: string;
    function GetCount: Integer; override;
    function GetEntity(const AIndex: Integer): TsgDXFEntity; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure SetBox(const ABox: TFRect);
    procedure SetEntity(const AIndex: Integer;
      const AEntity: TsgDXFEntity); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    procedure ToXMLSubEntities(const AParrentNode: TsgNode;
      const AMode: TsgXMLModes = cnstDefaultXMLMode); override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property View: TsgView read GetView;
    property BlockRecord: TsgDXFEntity read GetBlockRecord;
  public
    constructor Create; override;
    // functions of IsgListOfEntities
    function AddEntity(const AEntity: TsgDXFEntity): Integer; override;
    procedure Clear(const ADoFree: Boolean = True); override;
    function DeleteEntity(const AIndex: Integer): TsgDXFEntity; override;
    function IndexOfEntity(const AEntity: TsgDXFEntity): Integer; override;
    function IndexOfName(const AName: string): Integer; override;
    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; override;

    function UsingPlotSettings: Boolean;
    // function GetPlotWindowArea: TFRect;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    procedure Iterate(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc);
    function RotMatrix: TFMatrix;
    procedure SetRotMatrix(ARotMatrix: TFMatrix);
    property CADSpace: TsgCADSpace read FCADSpace write FCADSpace;
    property ExtMax: TFPoint read GetExtMax;
    property ExtMin: TFPoint read GetExtMin;
    property Index: Integer read GetIndex;
    property IsEmpty: Boolean read GetEmpty;
    property IsModel: Boolean read GetIsModel;
    property LinMax: TFPoint read GetLinMax;
    property LinMin: TFPoint read GetLinMin;
    property PaperSpaceBlock: TsgDXFBlock read GetPaperSpaceBlock
      write SetPaperSpaceBlock;
    property PlotSettings: TsgDXFPlotSettings read FPlotSettings
      write SetPlotSettings;
    // property PlotPaperUnits: Integer read GetPlotPaperUnits write SetPlotPaperUnits;
    property RotZAngle: Double read FRotZAngle write FRotZAngle;
    property UCSOrigin: TFPoint read FUCSOrigin write FUCSOrigin;
    property UCSXDir: TFPoint read FUCSXDir write FUCSXDir;
    property UCSYDir: TFPoint read FUCSYDir write FUCSYDir;
  end;

  TsgCADWipeout = class(TsgCADBasePolyline)
  private
    FClipPoints: TList;
    FClippingBoundaryType: Byte;
    FUseClipping: Boolean;
    function GetPointInternal(X, Y: Double): TFPoint;
    function GetClipPoint(Index: Integer): TF2DPoint;
    procedure SetClipPoint(Index: Integer; const P: TF2DPoint);
  protected
    FUVector: TFPoint;
    FVVector: TFPoint;
    FSize: TFPoint;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetClosed: Boolean; override;
    function GetEntType: TsgCADEntities; override;
    function GetClipPointsCount: Integer;
    function GetHeight: Double;
    function GetMatrix: TFMatrix;
    function GetPoint1: TFPoint;
    function GetPoint2: TFPoint;
    function GetPoint3: TFPoint;
    function GetWidth: Double;
    procedure ChangeSizes(K: Double);
{$IFNDEF EVG} procedure CreateDottedList; override; {$ENDIF}
    procedure ReloadPolyPoints; override;
    procedure SetClosed(const AClosed: Boolean); override;
    procedure SetHeight(const Value: Double);
    procedure SetWidth(const Value: Double);
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AddPoint(X, Y: Double);
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property ClipPoints[Index: Integer]: TF2DPoint read GetClipPoint
      write SetClipPoint; default;
    property ClipPointsCount: Integer read GetClipPointsCount;
    property Height: Double read GetHeight write SetHeight;
    property ClippingBoundaryType: Byte read FClippingBoundaryType
      write FClippingBoundaryType;
    property UVector: TFPoint read FUVector write FUVector;
    property UseClipping: Boolean read FUseClipping write FUseClipping;
    property VVector: TFPoint read FVVector write FVVector;
    property Width: Double read GetWidth write SetWidth;
    property Size: TFPoint read FSize write FSize;
  end;

  TsgDXFImageDef = class(TsgDXFOwneredItem)
  private
    FPicture: TPicture;
    FFileName: string;
    FReferences: TsgList;
    function GetReferences: TsgList;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetSize: TFPoint;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function EntName: string; override;
    property FileName: String read FFileName write FFileName;
    property Picture: TPicture read FPicture;
    property Size: TFPoint read GetSize;
    property References: TsgList read GetReferences;
  end;

  TsgDXFImageEnt = class(TsgCADWipeout)
  private
    FFlagsEx: Byte;
    FPicture: TPicture;
    FImageDef: TsgDXFImageDef;
    FImageDefExport: TsgDXFImageDef;
    FTransparentColor: Cardinal;
    procedure SetMonoChrome;
    procedure SetMnChrome(const AValue: Boolean);
    function GetInternal: Boolean;
    function GetMnChrome: Boolean;
    function GetRotate: Double;
    procedure SetImageDef(const Value: TsgDXFImageDef);
    procedure SetInternal(const AValue: Boolean);
    procedure SetRotate(const Value: Double);
    procedure SetDefaultTransparentColor(const Image: TGraphic;
      const ImageDef: TsgDXFImageDef);
  protected
    FImageProperties: PsgImageProperties;
    FDirectExportConverImageToOLE: Boolean; // Only for Direct export using
    FDirectExportImageFileIndex: Integer;
    FBitMap: TGraphic;
    FScaleMode: Integer;
{$IFDEF SG_USEGDIPLUS}
    FGDIDataHandle: HGlobal;
    FGDIPImage: TsgGDIPlusImage;
    procedure GDIPCreate;
    procedure GDIPFree;
{$ENDIF}
    procedure ChangeGraphic; virtual;
    procedure CreateImgLittle(const Scale: Integer);
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    procedure SetImgLittle(const ABitmap: TBitmap);
    function DoRotate(const Angle: Double;
      const AConverter: TsgDXFConverter): Boolean;
    function GetAnimate: Boolean; virtual;
    function GetEntType: TsgCADEntities; override;
    function GetTransparency: Boolean;
    function GetTransparentColor: Cardinal;
    function GroupExists: Boolean; override;
    function GroupCountEntities: Integer;
    function GroupFill(AConverter: TsgDXFConverter = nil): Boolean; override;
    function GroupHasAddedEntities: Boolean; override;
    procedure SetTransparency(const Value: Boolean);
    procedure SetTransparentColor(const AValue: Cardinal);
    procedure ApplyBox; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    function PictureUpdate(const ACADImage: TObject): Boolean; virtual;
    procedure RemoveReferenceNotification(const ARefObj: TsgDXFEntity);
      override;
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
    property ImageDefExport: TsgDXFImageDef read FImageDefExport
      write FImageDefExport; // only for internal using in the CADExport
    property Internal: Boolean read GetInternal write SetInternal;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function IsOnePixelOptimisationValid: Boolean; override; // evg
    function GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean; override;
    function EntName: string; override;
    procedure SetImage(Image: TGraphic);
    property ImageDef: TsgDXFImageDef read FImageDef write SetImageDef;
    property IsMonoChrome: Boolean read GetMnChrome write SetMnChrome;
    property Picture: TPicture read FPicture;
    property Point1: TFPoint read GetPoint1 write FUVector;
    property Point2: TFPoint read GetPoint2 write FVVector;
    property Point3: TFPoint read GetPoint3 write FSize;
    property Rotate: Double read GetRotate write SetRotate;
    property Transparency: Boolean read GetTransparency write SetTransparency;
    property TransparentColor: Cardinal read GetTransparentColor
      write SetTransparentColor;
  end;

  TsgDXFStyle = class(TsgDXFPenTableItem)
  private
    FBigFont: string;
    FFixedHeight: Single;
    FFontName: string;
    FFontStyle: TmvFontStyles;
    FLastHeightUsed: Single;
    FObliqueAngle: Single;
    FPrimaryFont: string;
    FSHXStyle: PsgTextStyle;
    FTextGenFlags: Byte;
    FWidthFactor: Single;
    function GetBackward: Boolean;
    function GetUpsideDown: Boolean;
    procedure SetPrimaryFont(const AValue: string);
  protected
    function BeginExtData(const AData: TsgCADExtendedData): Boolean; override;
    procedure EndExtData(const AData: TsgCADExtendedData); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure SetBackward(const AValue: Boolean);
    procedure SetUpsideDown(const AValue: Boolean);
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
    function FromXMLNode(const AType: TsgXMLType; const ANode: TsgNodeSample;
      const AIsChild: Boolean; const AResult: IsgResultNode = nil)
      : Integer; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetPrimaryFontName: string;
    function GetExtData(const AData: TsgCADExtendedData): Boolean; override;
    property Backward: Boolean read GetBackward write SetBackward;
    property BigFont: string read FBigFont write FBigFont;
    property FixedHeight: Single read FFixedHeight write FFixedHeight;
    property FontName: string read FFontName write FFontName;
    property FontStyle: TmvFontStyles read FFontStyle write FFontStyle;
    property LastHeightUsed: Single read FLastHeightUsed write FLastHeightUsed;
    property ObliqueAngle: Single read FObliqueAngle write FObliqueAngle;
    property PrimaryFont: string read FPrimaryFont write SetPrimaryFont;
    property SHXStyle: PsgTextStyle read FSHXStyle write FSHXStyle;
    property TextGenFlags: Byte read FTextGenFlags write FTextGenFlags;
    property WidthFactor: Single read FWidthFactor write FWidthFactor;
    property UpsideDown: Boolean read GetUpsideDown write SetUpsideDown;
  end;

  TTableSubclassMarker = (AcDbEntity, AcDbBlockReference, AcDbTable);

  TsgEnumCellsProc = function(ACol, ARow: Integer; AParam: Pointer)
    : Boolean of object;

(*$HPPEMIT 'struct TRange;'*)
(*$HPPEMIT 'typedef TRange *PRange;'*)
(*$HPPEMIT '#pragma pack(push,1)  '*)
(*$HPPEMIT 'struct TRange         '*)
(*$HPPEMIT '{                     '*)
(*$HPPEMIT 'union                 '*)
(*$HPPEMIT '{                     '*)
(*$HPPEMIT '		struct            '*)
(*$HPPEMIT '		{                 '*)
(*$HPPEMIT '			int Start[2];   '*)
(*$HPPEMIT '			int Finish[2];  '*)
(*$HPPEMIT '		};                '*)
(*$HPPEMIT '		struct            '*)
(*$HPPEMIT '		{                 '*)
(*$HPPEMIT '			Types::TRect R; '*)
(*$HPPEMIT '                      '*)
(*$HPPEMIT '		}*RANGE;                '*)
(*$HPPEMIT '	};                  '*)
(*$HPPEMIT '} ;                   '*)
(*$HPPEMIT '#pragma pack(pop)     '*)
  PRange = ^TRange;
{$EXTERNALSYM PRange}

  TRange = packed record
    case Integer of
      0:
        (R: TRect);
      1:
        (Start, Finish: array [Boolean] of Integer);
  end;
{$EXTERNALSYM TRange}

  TsgBorderProp = (bpColor, bpLineweight, bpVisible);

  PsgCellBorderParam = ^TsgCellBorderParam;

  TsgCellBorderParam = packed record
    Color: TsgColorCAD;
    LineWeight: Double;
    Visible: Boolean;
  end;

  TsgAcadTableCellType = (cttData, cttTitle, cttHeader);

  TsgCellProp = (cpCellAllignment, cpBkColorOn, cpTextStyle, cpTextColor,
    cpDataType, cpFillColor, cpUnitType);

  TsgAcadTableCellStyle = class;

  TsgAcadTableCell = class(TPersistent)
  private
    FAcadTable: TsgDXFAcadTable;
    FAttdefHandle: UInt64;
    FAttdefValue: string;
    FAutoFit: Boolean;
    FBlockRecordHandle: UInt64;
    FBlockScale: Single;
    FCellProps: TsgAcadTableCellStyle;
    FCellType: TsgAcadTableCellType;
    FCol: Integer;
    FField: TsgDXFField;
    FFlags: Integer;
    FIsTextType: Boolean;
    FMergedHeight: Integer;
    FMergedValue: Integer;
    FMergedWidth: Integer;
    FNumAttdefs: Integer;
    FOverrideFlag: Integer;
    FRotation: Single;
    FRow: Integer;
    FSpanX: Integer;
    FSpanY: Integer;
    FText: string;
    FVirtualEgdeFlag: Boolean;
    function GetBaseCell: TsgAcadTableCell;
    function GetBaseCellRange: TRect;
    function GetBkColorOn: Boolean;
    function GetBorderColor(Index: Integer): TsgColorCAD;
    function GetBorderLineWeight(Index: Integer): Double;
    function GetBorderPropOverridenMask(const ABorderProp: TsgBorderProp;
      const AIndex: Integer): Integer;
    function GetBorderVisible(Index: Integer): Boolean;
    function GetCellAlignment: Integer;
    function GetCellRange: TRect;
    function GetCellType: TsgAcadTableCellType;
    function GetDataType: Integer;
    function GetFillColor: TsgColorCAD;
    function GetFlags: Integer;
    function GetIsBaseCell: Boolean;
    function GetMerged: Boolean;
    function GetOwnerStyle: TsgAcadTableCellStyle;
    function GetTextColor: TsgColorCAD;
    function GetTextHeight: Double;
    function GetTextStyle: TsgDXFStyle;
    function GetUnitType: Integer;
    function IsBorderColorOverriden(const AIndex: Integer): Boolean;
    function IsBorderLineweightOverriden(const AIndex: Integer): Boolean;
    function IsBorderPropOverriden(const ABorderProp: TsgBorderProp;
      const AIndex: Integer): Boolean;
    function IsBorderVisibleOverriden(const AIndex: Integer): Boolean;
    procedure SetAttdefHandle(const AValue: UInt64);
    procedure SetAttdefValue(const AValue: string);
    procedure SetAutoFit(const AValue: Boolean);
    procedure SetBkColorOn(const AValue: Boolean);
    procedure SetBlockRecordHandle(const AValue: UInt64);
    procedure SetBlockScale(const AValue: Single);
    procedure SetBorderColor(Index: Integer; const AValue: TsgColorCAD);
    procedure SetBorderLineWeight(Index: Integer; const AValue: Double);
    procedure SetBorderVisible(Index: Integer; const AValue: Boolean);
    procedure SetCellAlignment(const AValue: Integer);
    procedure SetCellType(const AValue: TsgAcadTableCellType);
    procedure SetDataType(const AValue: Integer);
    procedure SetField(const AValue: TsgDXFField);
    procedure SetFillColor(const AValue: TsgColorCAD);
    procedure SetFlags(const AValue: Integer);
    procedure SetIsBaseCell(const AValue: Boolean);
    procedure SetIsTextType(const AValue: Boolean);
    procedure SetMergedHeight(const AValue: Integer);
    procedure SetMergedValue(const AValue: Integer);
    procedure SetMergedWidth(const AValue: Integer);
    procedure SetNumAttdefs(const AValue: Integer);
    procedure SetOverrideFlag(const AValue: Integer);
    procedure SetRotation(const AValue: Single);
    procedure SetText(const AValue: string);
    procedure SetTextColor(const AValue: TsgColorCAD);
    procedure SetTextHeight(const AValue: Double);
    procedure SetTextStyle(const AValue: TsgDXFStyle);
    procedure SetUnitType(const AValue: Integer);
    procedure SetVirtualEgdeFlag(const AValue: Boolean);
    function StyleByProp(const ACellProp: TsgCellProp): TsgAcadTableCellStyle;
    procedure UpdateFlags(const AIndex: Integer);
  protected
    function HasOwnerStyle: Boolean;
    function IsBorderEq(const AIndex: Integer;
      const ACell: TsgAcadTableCell): Boolean;
    function IsBorderEqEx(const AIndex: Integer;
      const AAdjacentCell: TsgAcadTableCell;
      const AAdjacentIndex: Integer): Boolean;
    function IsPropInit(const ACellProp: TsgCellProp): Boolean;
    function GenerateMText(const AConv: TsgDXFConverter;
      const AAcadTable: TsgDXFAcadTable): TsgDXFMText;
    function GetFlagsMask(AIndex: Integer): Integer;
    procedure Link(AConverter: TsgDXFConverter); virtual;
    property CellProps: TsgAcadTableCellStyle read FCellProps;
  public
    constructor Create(AAcadTable: TsgDXFAcadTable; const ACol, ARow: Integer;
      const ACellType: TsgAcadTableCellType = cttData);
    destructor Destroy; override;
    procedure Assign(ASource: TPersistent); override;
    function GetRect: TFRect;
    function GetMergedRect: TFRect;
    property AcadTable: TsgDXFAcadTable read FAcadTable;
    property AutoFit: Boolean read FAutoFit write SetAutoFit;
    property AttdefHandle: UInt64 read FAttdefHandle write SetAttdefHandle;
    property AttdefValue: string read FAttdefValue write SetAttdefValue;
    property BaseCell: TsgAcadTableCell read GetBaseCell;
    property BkColorOn: Boolean read GetBkColorOn write SetBkColorOn;
    property BlockRecordHandle: UInt64 read FBlockRecordHandle
      write SetBlockRecordHandle;
    property BlockScale: Single read FBlockScale write SetBlockScale;
    property BorderColor[Index: Integer]: TsgColorCAD read GetBorderColor
      write SetBorderColor;
    property BorderLineWeight[Index: Integer]: Double read GetBorderLineWeight
      write SetBorderLineWeight;
    property BorderVisible[Index: Integer]: Boolean read GetBorderVisible
      write SetBorderVisible;
    property BaseCellRange: TRect read GetBaseCellRange;
    property Col: Integer read FCol;
    property CellAlignment: Integer read GetCellAlignment
      write SetCellAlignment;
    property CellType: TsgAcadTableCellType read GetCellType write SetCellType;
    property CellRange: TRect read GetCellRange;
    property DataType: Integer read GetDataType write SetDataType;
    property Field: TsgDXFField read FField write SetField;
    property FillColor: TsgColorCAD read GetFillColor write SetFillColor;
    property Flags: Integer read GetFlags write SetFlags;
    property IsBaseCell: Boolean read GetIsBaseCell write SetIsBaseCell;
    property IsTextType: Boolean read FIsTextType write SetIsTextType;
    property Merged: Boolean read GetMerged;
    property MergedHeight: Integer read FMergedHeight write SetMergedHeight;
    property MergedValue: Integer read FMergedValue write SetMergedValue;
    property MergedWidth: Integer read FMergedWidth write SetMergedWidth;
    property NumAttdefs: Integer read FNumAttdefs write SetNumAttdefs;
    property OverrideFlag: Integer read FOverrideFlag write SetOverrideFlag;
    property Rotation: Single read FRotation write SetRotation;
    property Row: Integer read FRow;
    property SpanX: Integer read FSpanX write FSpanX;
    property SpanY: Integer read FSpanY write FSpanY;
    property Text: string read FText write SetText;
    property TextColor: TsgColorCAD read GetTextColor write SetTextColor;
    property TextHeight: Double read GetTextHeight write SetTextHeight;
    property TextStyle: TsgDXFStyle read GetTextStyle write SetTextStyle;
    property UnitType: Integer read GetUnitType write SetUnitType;
    property VirtualEgdeFlag: Boolean read FVirtualEgdeFlag
      write SetVirtualEgdeFlag;
  end;

  TsgDXFAcadTable = class(TsgDXFInsert)
  private
    FColWidth: TsgDoubleList;
    FFlags: Integer;
    FOverrideFlags: Byte;
    FProperties: TsgDXFAcadTableStyle;
    FRowHeight: TsgDoubleList;
    FRows: TList;
    FStyleRef: TsgDXFAcadTableStyle;
    function GetBaseCell(ACol, ARow: Integer): TsgAcadTableCell;
    function GetCell(ACol, ARow: Integer): TsgAcadTableCell;
    function GetColWidth(Index: Integer): Double;
    function GetNumCols: Integer;
    function GetNumRows: Integer;
    function GetPropertiesAcadTableStyle: TsgDXFAcadTableStyle;
    function GetRowHeight(Index: Integer): Double;
    function GetSizes(ANeedRowSize: Boolean; Index: Integer): Double;
    function GetStyle: TsgDXFAcadTableStyle;
    procedure SetCell(ACol, ARow: Integer; const AValue: TsgAcadTableCell);
    procedure SetColWidth(Index: Integer; const AValue: Double);
    procedure SetNumCols(const AValue: Integer);
    procedure SetNumRows(const AValue: Integer);
    procedure SetOverrideFlags(const AValue: Byte);
    procedure SetProperties(const AValue: TsgDXFAcadTableStyle);
    procedure SetRowHeight(Index: Integer; const AValue: Double);
    procedure SetSizes(ANeedRowSize: Boolean; Index: Integer;
      const AValue: Double);
    procedure SetStyle(const AValue: TsgDXFAcadTableStyle);
    { Enumeration handlers }
    function AssignCell(ACol, ARow: Integer; AParam: Pointer): Boolean;
    function MergeCell(ACol, ARow: Integer; AParam: Pointer): Boolean;
    function SetCellTextStyle(ACol, ARow: Integer; AParam: Pointer): Boolean;
    function SplitCell(ACol, ARow: Integer; AParam: Pointer): Boolean;
  protected
    FLockGenerateBlock: Boolean;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function CreateBlock(AConv: TsgDXFConverter): TsgDXFBlock;
    function EnumCells(AEnumCellsProc: TsgEnumCellsProc;
      AParam: Pointer): Boolean;
    function EnumRange(ARange: TRect; AEnumCellsProc: TsgEnumCellsProc;
      AParam: Pointer): Boolean;
    function GenerateMText(const AConv: TsgDXFConverter; ACol, ARow: Integer)
      : TsgDXFMText;
    function GetEntType: TsgCADEntities; override;
    function GetFlags: Integer; override;
    function GetUniqueBlockName(const AConv: TsgDXFConverter): string;
    function IsBlockInternal: Boolean;
    function ReleaseBlock: TsgDXFBlock;
    procedure SetFlags(const AValue: Integer); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
    procedure ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord); override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    procedure Clear(const ADoFree: Boolean = True); override;
    procedure MergeCells(const ACol, ARow, ASpanX, ASpanY: Integer);
    procedure SplitCells(ACol, ARow: Integer);

    function AddCol: Integer;
    function AddRow: Integer;
    procedure DeleteCol(ACol: Integer);
    procedure DeleteCols(AColFrom, AColTo: Integer);
    procedure DeleteRow(ARow: Integer);
    procedure DeleteRows(ARowFrom, ARowTo: Integer);
    procedure InsertRow(AIndex: Integer);
    procedure InsertCol(AIndex: Integer);

    procedure Resize(const AColCount, ARowCount: Integer);
    property BaseCell[ACol, ARow: Integer]: TsgAcadTableCell read GetBaseCell;
    property Cell[ACol, ARow: Integer]: TsgAcadTableCell read GetCell
      write SetCell;
    property ColWidth[Index: Integer]: Double read GetColWidth
      write SetColWidth;
    property NumCols: Integer read GetNumCols write SetNumCols;
    property NumRows: Integer read GetNumRows write SetNumRows;
    property OverrideFlags: Byte read FOverrideFlags write SetOverrideFlags;
    property Properties: TsgDXFAcadTableStyle read GetPropertiesAcadTableStyle
      write SetProperties;
    property RowHeight[Index: Integer]: Double read GetRowHeight
      write SetRowHeight;
    property Sizes[ANeedRowSize: Boolean; Index: Integer]: Double read GetSizes
      write SetSizes;
    property Style: TsgDXFAcadTableStyle read GetStyle write SetStyle;
  end;

  TsgAcadTableCellStyle = class(TPersistent)
  private
    FAcadTableStyle: TsgDXFAcadTableStyle;
    FBkColorOn: Boolean;
    FBorderParams: TList;
    FCellAlignment: Integer;
    FCellType: TsgAcadTableCellType;
    FDataType: Integer;
    FFillColor: TsgColorCAD;
    FCellInitProps: set of TsgCellProp;
    FTextColor: TsgColorCAD;
    FTextHeight: Double;
    FTextStyleItem: TsgTableItem;
    FUnitType: Integer;
    function GetBorderColor(Index: Integer): TsgColorCAD;
    function GetBorderCount: Integer;
    function GetBorderLineWeight(Index: Integer): Double;
    function GetBorderVisible(Index: Integer): Boolean;
    function GetTextStyle: TsgDXFStyle;
    procedure SetBkColorOn(const AValue: Boolean);
    procedure SetBorderColor(Index: Integer; const AValue: TsgColorCAD);
    procedure SetBorderLineWeight(Index: Integer; const AValue: Double);
    procedure SetBorderVisible(Index: Integer; const AValue: Boolean);
    procedure SetCellAlignment(const AValue: Integer);
    procedure SetCellType(const AValue: TsgAcadTableCellType);
    procedure SetDataType(const AValue: Integer);
    procedure SetFillColor(const AValue: TsgColorCAD);
    procedure SetTextColor(const AValue: TsgColorCAD);
    procedure SetTextHeight(const AValue: Double);
    procedure SetTextStyle(const AValue: TsgDXFStyle);
    procedure SetUnitType(const AValue: Integer);
  protected
    function IsPropInit(const ACellProp: TsgCellProp): Boolean;
    procedure SetPropInit(const ACellProp: TsgCellProp;
      const AInclude: Boolean);
    procedure Link(AConverter: TsgDXFConverter); virtual;
  public
    constructor Create(AAcadTableStyle: TsgDXFAcadTableStyle); overload;
    constructor Create(AAcadTableStyle: TsgDXFAcadTableStyle;
      const ACellType: TsgAcadTableCellType); overload;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    property AcadTableStyle: TsgDXFAcadTableStyle read FAcadTableStyle;
    property BkColorOn: Boolean read FBkColorOn write SetBkColorOn;
    property BorderColor[Index: Integer]: TsgColorCAD read GetBorderColor
      write SetBorderColor;
    property BorderCount: Integer read GetBorderCount;
    property BorderLineWeight[Index: Integer]: Double read GetBorderLineWeight
      write SetBorderLineWeight;
    property BorderVisible[Index: Integer]: Boolean read GetBorderVisible
      write SetBorderVisible;
    property CellAlignment: Integer read FCellAlignment write SetCellAlignment;
    property CellType: TsgAcadTableCellType read FCellType write SetCellType;
    property DataType: Integer read FDataType write SetDataType;
    property FillColor: TsgColorCAD read FFillColor write SetFillColor;
    property TextStyle: TsgDXFStyle read GetTextStyle write SetTextStyle;
    property TextColor: TsgColorCAD read FTextColor write SetTextColor;
    property TextHeight: Double read FTextHeight write SetTextHeight;
    property UnitType: Integer read FUnitType write SetUnitType;
  end;

  TsgDXFAcadTableStyle = class(TsgDXFOwneredItem)
  private
    FCellStyle: array [TsgAcadTableCellType] of TsgAcadTableCellStyle;
    FDescription: string;
    FFlags: Integer;
    FFlowDirection: Integer;
    FHeaderSuppressed: Boolean;
    FHorzCellMargin: Double;
    FTitleSuppressed: Boolean;
    FVertCellMargin: Double;
    function GetCellStyle(Index: TsgAcadTableCellType): TsgAcadTableCellStyle;
    procedure SetCellStyle(Index: TsgAcadTableCellType;
      const AValue: TsgAcadTableCellStyle);
    procedure SetDescription(const AValue: string);
    procedure SetFlowDirection(const AValue: Integer);
    procedure SetHeaderSuppressed(const AValue: Boolean);
    procedure SetHorzCellMargin(const AValue: Double);
    procedure SetTitleSuppressed(const AValue: Boolean);
    procedure SetVertCellMargin(const AValue: Double);
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetFlags: Integer; override;
    procedure SetFlags(const Value: Integer); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property HeaderSuppressed: Boolean read FHeaderSuppressed
      write SetHeaderSuppressed;
    property Description: string read FDescription write SetDescription;
    property FlowDirection: Integer read FFlowDirection write SetFlowDirection;
    property HorzCellMargin: Double read FHorzCellMargin
      write SetHorzCellMargin;
    property TitleSuppressed: Boolean read FTitleSuppressed
      write SetTitleSuppressed;
    property VertCellMargin: Double read FVertCellMargin
      write SetVertCellMargin;
    property CellStyle[Index: TsgAcadTableCellType]: TsgAcadTableCellStyle
      read GetCellStyle write SetCellStyle;
  end;

  TsgDXFProxy = class(TsgDXFPenLine)
  private
    FBox: TFRect;
    FEntities: TListNotify;
  protected
    procedure FreeReferences; override;
    function GetBox: TFRect; override;
    function GetCount: Integer; override;
    function GetEntity(const AIndex: Integer): TsgDXFEntity; override;
    function GetEntType: TsgCADEntities; override;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); override;
    function GroupExists: Boolean; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure SetEntity(const AIndex: Integer;
      const AEntity: TsgDXFEntity); override;
  public
    constructor Create; override;
    procedure Clear(const ADoFree: Boolean = True); override;
    function InsertEntity(const AIndex: Integer; const AEntity: TsgDXFEntity)
      : Boolean; override;
  end;

  TsgDXFSurface = class(TsgDXFProxy)
  protected
    function GetEntType: TsgCADEntities; override;
  end;

  { TsgFlatEntity }

  TsgFlatEntity = class(TsgDXFObjectEntityColor)
  private
    FBox: TFRect;
    FCounts: TsgIntegerList;
    FPoints: TsgBaseList;
    function GetXYLast: TFPoint;
  protected
    procedure AddFPoint(const APoint: TFPoint);
    procedure AddLine(const ALine: TsgDXFLine);
    procedure AddPoint(const X, Y: Double; const Z: Double = 0);
      virtual; abstract;
    procedure AddPoints(const APoints: TFPointList; const AClosed: Boolean;
      const ABox: PFRect = nil);
    procedure AddPolygon(P: TsgCADPolyPolygon);
    procedure AddPolyline(P: TsgCADBasePolyline);
    function CanDraw: Boolean; override;
    function CanHaveHandle: Boolean; override;
    procedure CopyProperty(const AEntity: TsgDXFEntity);
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetBox: TFRect; override;
    function GetXY(Index: Integer): TFPoint; virtual; abstract;
    function GetPointsSignleList: TsgSingleList; virtual;
    function GetPointsClass: TClass; virtual; abstract;
    function GroupExists: Boolean; override;
    function GroupFill(AConverter: TsgDXFConverter = nil): Boolean; override;
    function GroupHasAddedEntities: Boolean; override;
    procedure SetBox(const ABox: TFRect);
    procedure SetHandle(const Value: UInt64); override;
    procedure SetXY(Index: Integer; const Value: TFPoint); virtual; abstract;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function Accepts(const AEntity: TsgDXFEntity): Boolean; virtual;
    function Add(const AEntity: TsgDXFEntity): Boolean;
    function AddSegment(const APoints: TFPointList;
      const AMerge: Boolean): Boolean;
    function AddSegmentPoint(const APoint: TFPoint;
      const ACreateNewSegment: Boolean = False): Integer;
    function PCount: Integer; virtual;
    property Counts: TsgIntegerList read FCounts;
    property Points: TsgSingleList read GetPointsSignleList;
    property XY[Index: Integer]: TFPoint read GetXY write SetXY;
    property XYLast: TFPoint read GetXYLast;
  end;

  TsgFlatEntity2D = class(TsgFlatEntity)
  protected
    procedure AddPoint(const X, Y: Double; const Z: Double = 0); override;
    function GetPointsSignleList: TsgSingleList; override;
    function GetPointsClass: TClass; override;
    function GetXY(Index: Integer): TFPoint; override;
    procedure SetXY(Index: Integer; const Value: TFPoint); override;
  public
    function PCount: Integer; override;
    property Points: TsgSingleList read GetPointsSignleList;
  end;

  TsgFlatPoly = class(TsgFlatEntity2D)
  private
    FLineWeight: Double;
  protected
    function GetEntType: TsgCADEntities; override;
    function GetLineWeight: Double; override;
    function GroupFill(AConverter: TsgDXFConverter): Boolean; override;
    procedure SetLineWeight(Value: Double); override;
  public
    function Accepts(const AEntity: TsgDXFEntity): Boolean; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetThickness: Double; override;
  end;

  TsgFlatHatch = class(TsgFlatEntity2D)
  protected
    function GetEntType: TsgCADEntities; override;
    function GroupFill(AConverter: TsgDXFConverter = nil): Boolean; override;
  public
    function Accepts(const AEntity: TsgDXFEntity): Boolean; override;
  end;

  TsgFlatPoly3D = class(TsgFlatPoly)
  protected
    procedure AddPoint(const X, Y: Double; const Z: Double = 0); override;
    function GetXY(Index: Integer): TFPoint; override;
    function GetEntType: TsgCADEntities; override;
    function GetPointsSignleList: TsgSingleList; override;
    function GetPointsClass: TClass; override;
    procedure SetXY(Index: Integer; const Value: TFPoint); override;
  public
    function PCount: Integer; override;
  end;

  TsgSVGInsert = class(TsgDXFInsert)
  private
    FPrevMatrix: PFMatrix;
  protected
    procedure FreeReferences; override;
    procedure InitializeMatrix; override;
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetInitMatrix: TFMatrix;
    procedure SetInitMatrix(const AMatrix: TFMatrix);
  end;

  TsgSVGMText = class(TsgSVGInsert)
  protected
    procedure CopyItems(const ASource: TsgDXFEntity); override;
    procedure DoDelayedLoad(AConverter: TsgDXFConverter); override;
    procedure ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord); override;
  public
    constructor Create; override;
  end;

{$IFDEF SG_BTI}

  TsgCADPolyPolyline2D = class(TsgDXFObjectEntityLineType)
  private
    FBox: PFRect;
    FDotSingPts: TFPointList;
    FCurves: TList;
    FBoundary: TFPointList;
    FLineWeight: Double;
  protected
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function CanDraw: Boolean; override;
    function GetBox: TFRect; override;
    function GetDotSingPts: TFPointList; virtual;
    function GetCurveFlags(const AIndex: Integer): TsgCurveProperties;
    function GetEntType: TsgCADEntities; override;
    function GetArc(const AIndex: Integer): TsgArcR;
    function GetLine(const AIndex: Integer): TsgLine;
    function GetCurvesCount: Integer;
    function GetCurveJoin(const AIndex: Integer): Boolean;
    function GetCurvesVisible(const AIndex: Integer): Boolean;
    function GetLineWeight: Double; override;
    function GroupExists: Boolean; override;
    function GroupFill(AConverter: TsgDXFConverter = nil): Boolean; override;
    function GroupHasAddedEntities: Boolean; override;
    function IsLoaded: Boolean;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure LoadBoundary;
    procedure SetCurveFlags(const AIndex: Integer;
      const Value: TsgCurveProperties);
    procedure SetArc(const AIndex: Integer; const Value: TsgArcR);
    procedure SetLines(const AIndex: Integer; const Value: TsgLine);
    procedure SetCurveJoin(const AIndex: Integer; const Value: Boolean);
    procedure SetLineVisible(const AIndex: Integer; const Value: Boolean);
    procedure SetLineWeight(Value: Double); override;
    procedure SetHandle(const Value: UInt64); override;
    procedure ClearBox;
    procedure ClearBoundary;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    procedure AddCoords(const X1, Y1, X2, Y2: Double;
      const AFlags: TsgCurveProperties);
    procedure AddPoints(const AP1, AP2: TFPoint;
      const AFlags: TsgCurveProperties);
    procedure AddLine(const Value: TsgLine; const AFlags: TsgCurveProperties);
    procedure AddArc(const Arc: TsgArcR; const AFlags: TsgCurveProperties);
    procedure AddArcCoords(const X, Y, R, A1, A2: Double;
      const AFlags: TsgCurveProperties);
    procedure AddArcPoints(const AP: TFPoint; const R, A1, A2: Double;
      const AFlags: TsgCurveProperties);
    procedure Clear(const ADoFree: Boolean = True); override;
    procedure DeleteCurve(const AIndex: Integer);
    procedure GetBoundary(const AList: TList);
    procedure GetPointsOfArc(const AIndex: Integer;
      const A3DPointsList: TFPointList; const A2DPointsList: TsgIntegerList;
      NumberPart: Integer; Proc: TsgObjProcGetPoint = nil);
    function IsCurveArc(const AIndex: Integer): Boolean;
    property Boundary: TFPointList read FBoundary;
    property DotSingPts: TFPointList read GetDotSingPts;
    property LineType: TsgDXFLineType read GetLineType write SetLineType;
    property Arcs[const AIndex: Integer]: TsgArcR read GetArc write SetArc;
    property Lines[const AIndex: Integer]: TsgLine read GetLine write SetLines;
    property Flags[const AIndex: Integer]: TsgCurveProperties read GetCurveFlags
      write SetCurveFlags;
    property CurveJoin[const AIndex: Integer]: Boolean read GetCurveJoin
      write SetCurveJoin;
    property CurveVisible[const AIndex: Integer]: Boolean read GetCurvesVisible
      write SetLineVisible;
    property CurvesCount: Integer read GetCurvesCount;
  end;

  TsgAttribType = (atString, atEnum);
  PAttributeData = ^TAttributeData;

  TAttributeData = packed record
    AttribType: TsgAttribType;
    Name: string;
    Value: string;
    case TsgAttribType of
      atString:
        ();
      atEnum:
        (Values: TStringList);
  end;

  TsgAttrib = class(TsgDXFAttrib)
  private
    FType: TsgAttribType;
  protected
    function BeginExtData(const AData: TsgCADExtendedData): Boolean; override;
    procedure EndExtData(const AData: TsgCADExtendedData); override;
    function GetAttribIndex: Integer;
    function GetExBlockData: TsgExtendedBlockData;
    function GetIndexValue: Integer;
    function GetTypeValue: TsgAttribType;
    function GetValues: TStringList;
    procedure SetIndexValue(const AIndex: Integer);
    procedure SetTypeValue(const Value: TsgAttribType);
    property AttribIndex: Integer read GetAttribIndex;
    property ExBlockData: TsgExtendedBlockData read GetExBlockData;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    function GetExtData(const AData: TsgCADExtendedData): Boolean; override;
    property Values: TStringList read GetValues;
    property IndexValue: Integer read GetIndexValue write SetIndexValue;
    property TypeValue: TsgAttribType read GetTypeValue write SetTypeValue;
  end;

  TsgGroup = class(TsgDXFInsert)
  protected
    function AddBlock(const AConverter: TsgDXFConverter): Boolean;
    function CanFreeBlock(AConverter: TsgDXFConverter): Boolean;
    function CanLoading(AConverter: TsgDXFConverter): Boolean;
    procedure CreateBlock;
    procedure ClearBlock; virtual;
    function FreeBlock: Boolean;
    function ReMoveBlock(const AConverter: TsgDXFConverter): Boolean;
    procedure ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord); override;
    function ShortName: string; virtual;
  public
    constructor Create; override;
    destructor Destroy; override;
  end;

  TsgLabel = class(TsgGroup)
  private
    FFlags: Byte;
    FHeight: TsgFloat;
    FTextStyleItem: TsgTableItem;
    FTextLeft: string;
    FTextRight: string;
    FTextTop: string;
    FTextBottom: string;
    FTextOffset: TsgFloat;
    FEntOwner: TsgDXFEntity;
    function GenerateLabel(const AConverter: TsgDXFConverter): Boolean;
  protected
    function BeginExtData(const AData: TsgCADExtendedData): Boolean; override;
    procedure EndExtData(const AData: TsgCADExtendedData); override;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    function GetAlign: Byte;
    function GetEntType: TsgCADEntities; override;
    function GetEntTypeEx: Integer; override;
    function GetHeight: TsgFloat;
    function GetTextLeft: string;
    function GetTextRight: string;
    function GetTextTop: string;
    function GetTextBottom: string;
    function GetTextLeftShow: string; virtual;
    function GetTextRightShow: string; virtual;
    function GetTextTopShow: string; virtual;
    function GetTextBottomShow: string; virtual;
    function GetShowSplitter: Boolean;
    function GetStyle: TsgDXFStyle;
    function GetTextOffset: TsgFloat;
    function GetEntClassEx: TsgEntClass; override;
    procedure SetAlign(const Value: Byte);
    procedure SetHeight(const Value: TsgFloat);
    procedure SetTextLeft(const Value: string);
    procedure SetTextRight(const Value: string);
    procedure SetTextTop(const Value: string);
    procedure SetTextBottom(const Value: string);
    procedure SetShowSplitter(const Value: Boolean);
    procedure SetStyle(const Value: TsgDXFStyle);
    procedure SetTextOffset(const Value: TsgFloat);
    function ShortName: string; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure Link(AConverter: TsgDXFConverter); override;
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    procedure CopyFrom(Source: TsgLabel);
    function GetExtData(const AData: TsgCADExtendedData): Boolean; override;
    function EntName: string; override;
    property Align: Byte read GetAlign write SetAlign;
    property Height: TsgFloat read GetHeight write SetHeight;
    property EntOwner: TsgDXFEntity read FEntOwner write FEntOwner;
    property TextLeft: string read GetTextLeft write SetTextLeft;
    property TextRight: string read GetTextRight write SetTextRight;
    property TextTop: string read GetTextTop write SetTextTop;
    property TextBottom: string read GetTextBottom write SetTextBottom;
    property TextLeftShow: string read GetTextLeftShow;
    property TextRightShow: string read GetTextRightShow;
    property TextTopShow: string read GetTextTopShow;
    property TextBottomShow: string read GetTextBottomShow;
    property ShowSplitter: Boolean read GetShowSplitter write SetShowSplitter;
    property Style: TsgDXFStyle read GetStyle write SetStyle;
    property TextOffset: TsgFloat read GetTextOffset write SetTextOffset;
  end;

  TsgAreaFigure = class
  private
    function GetArea: Double;
    function GetSign: Integer;
    procedure SetSign(const Value: Integer);
    function GetName: string;
    function GetPerimeter: Double;
    procedure SetKoef(const Value: Double);
  protected
    FFlags: Byte;
    FKoef: Double;
    FName: string;
    FParams: array [0 .. 3] of Double;
    FType: TsgFigureType;
    function GetExtData(const AData: TsgCADExtendedData): Boolean; virtual;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(const AObj: TObject);
    function GetAreaStr(const APrecition: Integer;
      const ASeparator: Char = ','): string;
    function GetFormula(const APrecition: Integer;
      const ASeparator: Char = ','): string;
    function GetInfo(const APrecition: Integer;
      const ASeparator: Char = ','): string;
    property Area: Double read GetArea;
    property FigureType: TsgFigureType read FType write FType;
    property Koef: Double read FKoef write SetKoef;
    property Name: string read GetName write FName;
    property Perimeter: Double read GetPerimeter;
    property Sign: Integer read GetSign write SetSign;
    property A: Double read FParams[0] write FParams[0];
    property B: Double read FParams[1] write FParams[1];
    property C: Double read FParams[2] write FParams[2];
    property D: Double read FParams[3] write FParams[3];
    property H: Double read FParams[2] write FParams[2];
    property L: Double read FParams[1] write FParams[1];
    property R: Double read FParams[1] write FParams[1];
    property S: Double read FParams[0] write FParams[0];
    property P: Double read FParams[1] write FParams[1];
  end;

  TsgExtendedBlockData = class
  private
    FFlags: Byte;
    FLineTypeItem: TsgTableItem;
    function GetAlignment: Boolean;
    function GetArea: Boolean;
    function GetAttribute(AIndex: Integer): TAttributeData;
    function GetAttributesCount: Integer;
    function GetBroad: Boolean;
    function GetCarvingMode: Byte;
    function GetCircular: Boolean;
    function GetComplex: Boolean;
    function GetFillColor: TColor;
    function GetFillColorCAD: TsgColorCAD;
    function GetInsUnits: TsgInsUnits;
    function GetLength: Double;
    function GetLineType: TsgDXFLineType;
    function GetValueMask: string;
    function GetSegmentsCount: Integer;
    function GetSegmentWidths: TF2DRect;
    function GetSize: TF2DPoint;
    function GetTypeSnapEntities: Integer;
    function GetWidth: Double;
    procedure SetAlignment(const Value: Boolean);
    procedure SetAttribute(AIndex: Integer; const Value: TAttributeData);
    procedure SetCarvingMode(const Value: Byte);
    procedure SetCircular(const Value: Boolean);
    procedure SetFillColor(const Value: TColor);
    procedure SetFillColorCAD(const Value: TsgColorCAD);
    procedure SetInsUnits(const Value: TsgInsUnits);
    procedure SetLength(const Value: Double);
    procedure SetLineType(const Value: TsgDXFLineType);
    procedure SetValueMask(const Value: string);
    procedure SetSegmentsCount(const Value: Integer);
    procedure SetTypeSnapEntities(const Value: Integer);
    procedure SetWidth(const Value: Double);
    procedure SetSegmentWidths(const Value: TF2DRect);
    procedure SetSize(const Value: TF2DPoint);
    procedure SetParent(const AValue: TsgDXFBlock);
  protected
    FAlignment: PBoolean;
    FAttribs: TList;
    FCarvingMode: PByte;
    FFillColor: PsgColorCAD;
    FIsCircular: PBoolean;
    FInsUnits: PByte;
    FLength: PDouble;
    FValueMask: string;
    FSegmentsCount: PInteger;
    FSegmentWidths: PF2DRect;
    FTypeSnapEntities: PInteger;
    FWidth: PDouble;
    FParent: TsgDXFBlock;
  public
    constructor Create;
    destructor Destroy; override;
    procedure ClearAttribs;
    procedure DeleteAttribute(AIndex: Integer);
    procedure AddAttribute(const AName, AValue: string; AType: TsgAttribType;
      ValuesList: TStringList = nil; const ASort: Boolean = False);
    procedure Assign(const Source: TsgExtendedBlockData);
    function GetXML: string;
    function SetXML(AXML: string; AConv: TsgDXFConverter): Boolean;
    function HasSegmentWidths: Boolean;
    property Alignment: Boolean read GetAlignment write SetAlignment;
    property Attributes[AIndex: Integer]: TAttributeData read GetAttribute
      write SetAttribute;
    property AttributesCount: Integer read GetAttributesCount;
    property CarvingMode: Byte read GetCarvingMode write SetCarvingMode;
    property FillColor: TColor read GetFillColor write SetFillColor;
    property FillColorCAD: TsgColorCAD read GetFillColorCAD
      write SetFillColorCAD;
    property Flags: Byte read FFlags write FFlags;
    property InsUnits: TsgInsUnits read GetInsUnits write SetInsUnits;
    property IsArea: Boolean read GetArea;
    property IsBroad: Boolean read GetBroad;
    property IsCircular: Boolean read GetCircular write SetCircular;
    property IsComplex: Boolean read GetComplex;
    property Length: Double read GetLength write SetLength;
    property LineType: TsgDXFLineType read GetLineType write SetLineType;
    property SegmentsCount: Integer read GetSegmentsCount
      write SetSegmentsCount;
    property SegmentWidths: TF2DRect read GetSegmentWidths
      write SetSegmentWidths;
    property Size: TF2DPoint read GetSize write SetSize;
    property TypeSnapEntities: Integer read GetTypeSnapEntities
      write SetTypeSnapEntities;
    property Parent: TsgDXFBlock read FParent write SetParent;
    property ValueMask: string read GetValueMask write SetValueMask;
    property Width: Double read GetWidth write SetWidth;
  end;
{$ENDIF}

  TsgBrepEntity = class(TsgDXFGroup)
  private
    FPen: TsgDXFPenLine;
    FLastGroupIndex: Integer;
    procedure SetParamsByMeshBuilder(AParams: PsgParamTriangle;
      AInitData: PsgInitMeshBuilderData);
  protected
    function CanDraw: Boolean; override;
    procedure ClearReferences; override;
    procedure FreeReferences; override;
    procedure Invoke(AConverter: TsgDXFConverter;
      Proc, FinishProc: TsgCADEntityProc); override;
    // procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure MeshBrepBuilder(const AInitParam: TsgInitParam;
      const AData: TsgInitMeshBuilderData;
      const ADeviationCoefficien: Double = 0.001); virtual;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure GroupClear; override;
    function GroupInternalEntities(AConverter: TsgDXFConverter): Boolean;
    function GetColorCAD: TsgColorCAD; override;
    function GetExtrusion: TFPoint; override;
    function GetLines: TsgLines; override;
    function GetLineType: TsgDXFLineType; override;
    function GetLineTypeScale: Double; override;
    procedure SetColorCAD(const Value: TsgColorCAD); override;
    procedure SetLineType(const AValue: TsgDXFLineType); override;
    procedure SetLineTypeScale(Value: Double); override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    procedure GetMeshBrep(const AData: TsgInitMeshBuilderData;
      const ADeviationCoefficien: Double = 0.001);
    property Pen: TsgDXFPenLine read FPen;
    property Extrusion: TFPoint read GetExtrusion;
  end;

  TsgDXFACISEntity = class(TsgBrepEntity)
  private
    FEncoded: Boolean;
    FProprietaryData: TStringList;
    FProprietaryDataDecoded: Boolean;
    FIncorrectAttribsChecked: Boolean;
    FDelimiter: Char;
    FEofStr: Char;
    FSATDirect: Boolean;
    FBrepRoot: TsgDXFEntity;
    FParcingConverter: TsgDXFConverter;
    FIndexFaceMap: TList;
{$IFDEF SG_CADIMPORTER_DLL}
    FSATStrings: string;
{$ENDIF}
    procedure SetProprietaryData(const AValue: TStringList);
  protected
    procedure ClearReferences; override;
    function GroupExists: Boolean; override;
    procedure FreeReferences; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
    procedure MeshBrepBuilder(const AInitParam: TsgInitParam;
      const AData: TsgInitMeshBuilderData;
      const ADeviationCoefficien: Double = 0.001); override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    procedure Clear(const ADoFree: Boolean = True); override;
    procedure LoadFromFile(const FileName: string);
    procedure LoadFromMemory(Mem: Pointer; Size: Integer;
      ASATDirect: Boolean = True);
    procedure LoadFromStream(const AStream: TStream;
      ASATDirect: Boolean = True);
    property Brep: TsgDXFEntity read FBrepRoot;
    property Encoded: Boolean read FEncoded write FEncoded;
    property Delimiter: Char read FDelimiter write FDelimiter;
    property EofStr: Char read FEofStr write FEofStr;
    property IncorrectAttribsChecked: Boolean read FIncorrectAttribsChecked
      write FIncorrectAttribsChecked;
    property ProprietaryData: TStringList read FProprietaryData
      write SetProprietaryData;
    property ProprietaryDataDecoded: Boolean read FProprietaryDataDecoded
      write FProprietaryDataDecoded;
    property SATDirect: Boolean read FSATDirect write FSATDirect;
{$IFDEF SG_CADIMPORTER_DLL}
    property SATStrings: string read FSATStrings;
{$ENDIF}
  end;

  TsgDXFACISIndexFace = class(TsgBrepEntity)
  private
    FOwner: TsgDXFACISEntity;
    FIndexFaceMap: Integer;
{$IFDEF SG_BREP_TOPOLOGY}
    FArea: Double;
{$ENDIF}
  protected
    function GetEntType: TsgCADEntities; override;
    function GroupExists: Boolean; override;
    function GroupFill(AConverter: TsgDXFConverter = nil): Boolean; override;
    function GroupHasAddedEntities: Boolean; override;
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
{$IFDEF SG_BREP_TOPOLOGY}
    property Area: Double read FArea write FArea;
{$ENDIF}
    property IndexFaceMap: Integer read FIndexFaceMap write FIndexFaceMap;
    property Owner: TsgDXFACISEntity read FOwner write FOwner;
  end;

  TsgBrepGroup = class(TsgBrepEntity)
  private
    FName: string;
    FContext: TsgContext;
  protected
    function GroupExists: Boolean; override;
    function GetContext: PsgContext; virtual;
    procedure MeshBrepBuilder(const AInitParam: TsgInitParam;
      const AData: TsgInitMeshBuilderData;
      const ADeviationCoefficien: Double = 0.001); override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property FileName: string read FName write FName;
  end;

  TsgBrepIges = class(TsgBrepGroup)
  protected
    function GetEntType: TsgCADEntities; override;
  end;

  TsgBrepStep = class(TsgBrepGroup)
  protected
    function GetEntType: TsgCADEntities; override;
  end;

  TsgBrepBrep = class(TsgBrepGroup)
  protected
    function GetEntType: TsgCADEntities; override;
  end;

  TsgBrepGroupChild = class(TsgBrepGroup)
  private
    FOwner: TsgBrepGroup;
  protected
    function GetContext: PsgContext; override;
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property Owner: TsgBrepGroup read FOwner write FOwner;
  end;

  TsgBrepIndexFace = class(TsgBrepGroupChild)
  private
    FIndexFaceMap: Integer;
{$IFDEF SG_BREP_TOPOLOGY}
    FReferenceToTopology: TsgDXFEntity; // TsgBrepObjectTopology
    FArea: Double;
{$ENDIF}
  protected
    function GetEntType: TsgCADEntities; override;
    function GroupExists: Boolean; override;
    function GroupFill(AConverter: TsgDXFConverter = nil): Boolean; override;
    function GroupHasAddedEntities: Boolean; override;
  public
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property IndexFaceMap: Integer read FIndexFaceMap write FIndexFaceMap;
{$IFDEF SG_BREP_TOPOLOGY}
    property Area: Double read FArea write FArea;
    property ReferenceToTopology: TsgDXFEntity read FReferenceToTopology
      write FReferenceToTopology;
{$ENDIF}
  end;

{$IFDEF SG_BREP_TOPOLOGY}

  TsgBrepObjectTopology = class(TsgBrepGroupChild)
  private
    FCenterMass: TFPoint;
    FVolume: Double;
    FArea: Double;
    FOriginalName: string;
    FReferenceToContainer: TsgDXFEntity; // Block for which the calculation
  protected
    function ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = [])
      : Integer; override;
  public
    property CenterMass: TFPoint read FCenterMass write FCenterMass;
    property Volume: Double read FVolume write FVolume;
    property Area: Double read FArea write FArea;
    property OriginalName: string read FOriginalName write FOriginalName;
    property ReferenceToContainer: TsgDXFEntity read FReferenceToContainer
      write FReferenceToContainer;
  end;
{$ENDIF}

  TsgDXFRegion = class(TsgDXFACISEntity)
  protected
    function GetEntType: TsgCADEntities; override;
    procedure LoadedInternal(AConverter: TsgDXFConverter); override;
  end;

  TsgDXF3dSolid = class(TsgDXFACISEntity)
  protected
    function GetEntType: TsgCADEntities; override;
  end;

  TsgDXFBody = class(TsgDXFACISEntity)
  protected
    function GetEntType: TsgCADEntities; override;
  end;

  PsgTexVertex4f = ^TsgTexVertex4f;

  TsgTexVertex4f = record
    case Integer of
      0:
        (X, Y, Z, W: Single);
      1:
        (V: array [0 .. 3] of Single)
  end;

  PsgTexMatrix4f = ^TsgTexMatrix4f;

  TsgTexMatrix4f = record
    case Integer of
      0:
        (V1, V2, V3, V4: TsgTexVertex4f);
      1:
        (M: array [0 .. 3, 0 .. 3] of Single);
      2:
        (V: array [0 .. 3] of TsgTexVertex4f)
  end;

  TsgCustomMaterialColor = class(TPersistent)
  protected
    function GetColor: TsgColorCAD; virtual;
    function GetFactor: Double; virtual;
    procedure SetColor(const Value: TsgColorCAD); virtual;
    procedure SetFactor(const Value: Double); virtual;
    function GetMethod: Integer; virtual;
    procedure SetMethod(const Value: Integer); virtual;
  public
    constructor Create; virtual;
    property Color: TsgColorCAD read GetColor write SetColor;
    property Factor: Double read GetFactor write SetFactor;
    property Method: Integer read GetMethod write SetMethod;
  end;

  TsgMaterialColor = class(TsgCustomMaterialColor)
  private
    FColor: TsgColorCAD;
    FFactor: Double;
    FMethod: Integer; // 0..1
  protected
    function GetColor: TsgColorCAD; override;
    function GetFactor: Double; override;
    procedure SetColor(const Value: TsgColorCAD); override;
    procedure SetFactor(const Value: Double); override;
    function GetMethod: Integer; override;
    procedure SetMethod(const Value: Integer); override;
  public
    constructor Create; override;
    procedure Assign(Source: TPersistent); override;
  end;

  TsgMaterialMapper = class(TPersistent)
  private
    FTransform: TsgTexMatrix4f;
    FAutoTransform: Byte;
    FProjection: Byte;
    FTiling: Byte;
    function GetMatrix(I, J: Integer): Single;
    procedure SetTransform(const Value: TsgTexMatrix4f);
    procedure SetAutoTransform(const Value: Byte);
    procedure SetProjection(const Value: Byte);
    procedure SetTiling(const Value: Byte);
    procedure SetMatrix(I, J: Integer; const Value: Single);
    function GetAsAddress: PSingle;
  public
    constructor Create; virtual;
    procedure Assign(Source: TPersistent); override;
    property AutoTransform: Byte read FAutoTransform write SetAutoTransform;
    property Projection: Byte read FProjection write SetProjection;
    property Tiling: Byte read FTiling write SetTiling;
    property Transform: TsgTexMatrix4f read FTransform write SetTransform;
    property Matrix[I, J: Integer]: Single read GetMatrix
      write SetMatrix; default;
    property AsAddress: PSingle read GetAsAddress;
  end;

  TsgMaterialMap = class(TPersistent)
  private
    FBlend: Double;
    FFileName: string;
    FMapper: TsgMaterialMapper;
    FMapSource: Integer;
    FMaterialColor: TsgCustomMaterialColor;
    FXrecordItem: TsgTableItem;
    function GetXrecord: TsgDXFXRecord;
    procedure SetBlend(const Value: Double);
    procedure SetFileName(const Value: string);
    procedure SetMapper(const Value: TsgMaterialMapper);
    procedure SetMapSource(const Value: Integer);
    procedure SetMaterialColor(const Value: TsgCustomMaterialColor);
    procedure SetXrecord(const Value: TsgDXFXRecord);
  protected
    function CreateMaterialColor: TsgCustomMaterialColor; virtual;
  public
    constructor Create; virtual;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    property Blend: Double read FBlend write SetBlend;
    property MaterialColor: TsgCustomMaterialColor read FMaterialColor
      write SetMaterialColor;
    property FileName: string read FFileName write SetFileName;
    property Mapper: TsgMaterialMapper read FMapper write SetMapper;
    property MapSource: Integer read FMapSource write SetMapSource;
    property Xrecord: TsgDXFXRecord read GetXrecord write SetXrecord;
  end;

  TsgColoredMaterialMap = class(TsgMaterialMap)
  protected
    function CreateMaterialColor: TsgCustomMaterialColor; override;
  end;

  TsgAmbientMaterialMap = class(TsgColoredMaterialMap);

  TsgDiffuseMaterialMap = class(TsgColoredMaterialMap)
  private
    FBleed: TsgCustomMaterialColor;
    FIndirectDump: TsgCustomMaterialColor;
    FNormal1: TsgCustomMaterialColor;
    FNormal2: TsgCustomMaterialColor;
    FReflectanceScale: Double;
    FLuminance: Double;
    FTransmittanceScale: Double;
    procedure SetBleed(const Value: TsgCustomMaterialColor);
    procedure SetIndirectDump(const Value: TsgCustomMaterialColor);
    procedure SetLuminance(const Value: Double);
    procedure SetReflectanceScale(const Value: Double);
    procedure SetTransmittanceScale(const Value: Double);
    procedure SetNormal1(const Value: TsgCustomMaterialColor);
    procedure SetNormal2(const Value: TsgCustomMaterialColor);
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    property Bleed: TsgCustomMaterialColor read FBleed write SetBleed;
    property IndirectDump: TsgCustomMaterialColor read FIndirectDump
      write SetIndirectDump;
    property Normal1: TsgCustomMaterialColor read FNormal1 write SetNormal1;
    property Normal2: TsgCustomMaterialColor read FNormal2 write SetNormal2;
    property ReflectanceScale: Double read FReflectanceScale
      write SetReflectanceScale;
    property TransmittanceScale: Double read FTransmittanceScale
      write SetTransmittanceScale;
    property Luminance: Double read FLuminance write SetLuminance;
  end;

  TsgSpecularMaterialMap = class(TsgColoredMaterialMap)
  private
    FGloss: Double;
    procedure SetGloss(const Value: Double);
  public
    constructor Create; override;
    procedure Assign(Source: TPersistent); override;
    property Gloss: Double read FGloss write SetGloss;
  end;

  TsgReflectionMaterialMap = class(TsgMaterialMap);

  TsgOpacityMaterialMap = class(TsgMaterialMap)
  private
    FPercent: Double;
    procedure SetPercent(const Value: Double);
  public
    constructor Create; override;
    procedure Assign(Source: TPersistent); override;
    property Percent: Double read FPercent write SetPercent;
  end;

  TsgBumpMaterialMap = class(TsgMaterialMap);

  TsgRefractionMaterialMap = class(TsgMaterialMap)
  private
    FIndex: Double;
    procedure SetIndex(const Value: Double);
  public
    procedure Assign(Source: TPersistent); override;
    property Index: Double read FIndex write SetIndex;
  end;

  TsgDXFMaterial = class(TsgDXFOwneredItem)
  private
    FAmbient: TsgAmbientMaterialMap;
    FDiffuse: TsgDiffuseMaterialMap;
    FSpecular: TsgSpecularMaterialMap;
    FReflection: TsgReflectionMaterialMap;
    FOpacity: TsgOpacityMaterialMap;
    FBump: TsgBumpMaterialMap;
    FRefraction: TsgRefractionMaterialMap;
    procedure SetAmbient(const Value: TsgAmbientMaterialMap);
    procedure SetDiffuse(const Value: TsgDiffuseMaterialMap);
    procedure SetSpecular(const Value: TsgSpecularMaterialMap);
    procedure SetReflection(const Value: TsgReflectionMaterialMap);
    procedure SetOpacity(const Value: TsgOpacityMaterialMap);
    procedure SetBump(const Value: TsgBumpMaterialMap);
    procedure SetRefraction(const Value: TsgRefractionMaterialMap);
  protected
    procedure FreeReferences; override;
  public
    constructor Create; override;
    procedure AssignEntity(Source: TsgDXFEntity); override;
    property Ambient: TsgAmbientMaterialMap read FAmbient write SetAmbient;
    property Bump: TsgBumpMaterialMap read FBump write SetBump;
    property Diffuse: TsgDiffuseMaterialMap read FDiffuse write SetDiffuse;
    property Opacity: TsgOpacityMaterialMap read FOpacity write SetOpacity;
    property Reflection: TsgReflectionMaterialMap read FReflection
      write SetReflection;
    property Refraction: TsgRefractionMaterialMap read FRefraction
      write SetRefraction;
    property Specular: TsgSpecularMaterialMap read FSpecular write SetSpecular;
  end;

  TBufferedStream = class(TStream)
  private
    FStream: TStream;
    // FOffset: Int64;
    FBuffer: PAnsiChar;
    FBufPtr: PAnsiChar;
    FBufEnd: PAnsiChar;
    FBufSize: Integer;
    function Overflow: Boolean;
    function Underflow: Boolean;
    function GetByte(var Buffer): Boolean;
    function PutByte(const Buffer): Boolean;
  public
    constructor Create(AStream: TStream; ABufSize: Integer);
    destructor Destroy; override;
    function Read(var Buffer; Count: Longint): Longint; override;
    function Write(const Buffer; Count: Longint): Longint; override;
{$IFNDEF SGDEL_6}
    function Seek(Offset: Longint; Origin: Word): Longint; override;
{$ELSE}
    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
{$ENDIF}
  end;

  TCustomAlignedDataReader = class(TInterfacedObject, IProxyReader)
  private
    FVersion: TsgDWGVersion;
    procedure ReadRaw(const ALen: Integer; var AStr: sgRawByteString);
    procedure ReadWideRaw(const ALen: Integer; var AStr: WideString);
  protected
    FPos: Pointer;
    FStack: Pointer;
    function ReadDouble: Double; virtual;
    function ReadInteger: Integer; virtual;
    function ReadSmallInt: SmallInt; virtual;
    function ReadWord: Word; virtual;
    function ReadByte: Byte; virtual;
    procedure PushPosition; virtual;
    procedure PopPosition; virtual;
    procedure Seek(ASize: Integer); virtual;
    function ReadAnsiPadding: AnsiString; virtual;
    function ReadString: string; virtual;
    function ReadHandle: UInt64; virtual;
    procedure ReadBytes(var Dest; const ACount: UInt64); virtual;
    function Position: Pointer; virtual;
    property Version: TsgDWGVersion read FVersion write FVersion;
  public
    constructor Create(APos: Pointer; AVersion: TsgDWGVersion); virtual;
  end;

function UnitRect: TFRect;
function SGArcCos(const X: Double): Double;
function GetVertex(AList: TList; Index: Integer; const ASy: Double)
  : PsgSHXVertex;
function GetExportImageIndex(I: TsgDXFImageEnt; AIndex: Integer;
  ConverImageToOLE: Boolean): Integer;

function EntArc(E: TsgDXFArc; P: TsgCADIterate): TsgArc;
function EntColor(E: TsgDXFEntity; Ins: TsgDXFInsert): TColor;
function EntLayer(E: TsgDXFEntity; Ins: TsgDXFInsert): TsgDXFLayer;
function EntLineWeight(E: TsgDXFEntity; Ins: TsgDXFInsert): Double;
function EntStyle(E: TsgDXFEntity): TPenStyle;
function EntXrefBlock(E: TsgDXFEntity; Converter: TsgDXFConverter)
  : TsgDXFBlockRecord;
function BSwap(Value: Integer): Integer;
// function StrPos(Str1, Str2, Limit: PChar): PChar;
function StrIndex(const S: string; const Map: array of string): Integer;
{$IFDEF USE_INLINE}inline; {$ENDIF}
procedure SubStr(var S: AnsiString; var P: PAnsiChar; Limit: PAnsiChar);

procedure ApplyBulge(const P1, P2: TFPoint; const Bulge: Double;
  const AList: TList; const ANumberOfCircleParts: Integer;
  const AGetPointProc: TsgCreatePPoint; var AResultArc: TsgArcR);
function BulgeByArc(AArc: TsgArcR; AVertexPoint: TFPoint;
  const Epsilon: Double = fDoubleResolution): Double;
function GetArcROfVertexes(const AVertex1, AVertex2: TsgDXFVertex;
  var AArc: TsgArcR): Boolean;
procedure GenerateLineTypes(AConverter: TsgDXFConverter;
  const AComplex: Boolean);
procedure GenerateLineTypesEx(const AConverter: TsgDXFConverter;
  const APrefix: string; const AComplex, AIsUniform: Boolean);
procedure GetSinglePts(APts: array of TFPoint; AList: TList);
function GetTextAlignedRotation(const ATextAlign: Integer;
  const ARotation: Double): Double;
procedure OffsetFRect(var R: TFRect; DX, DY, DZ: Extended);
procedure DoScale2D(var P: TsgCADIterate);
procedure TextParms(var P: TsgCADIterate); // is equal DoScale2D
procedure UnionFRect(var Dst: TFRect; const Src: TFRect);
function ConvertDoubleToSingle(const ADouble: Double): Single;

function CircleFromThreePoints(APoly: TsgDXFPolyline; const P1, P2, P3: TFPoint;
  const APartsNumber: Integer; const AIsCircle: Boolean): Boolean;
function ArcFromTwoVectors(APoly: TsgDXFPolyline;
  const ARadius, ASweepAngle: Double; const ACenter, ANormalVector,
  AStartVector: TFPoint; APartsNumber: Integer): Boolean;

function IsFileOnWeb(const AFileName: string): Boolean;
function LoadPictureFromDisk(const APicture: TPicture;
  const AFileName: string): Boolean;
function LoadPictureFromWEB(const APicture: TPicture;
  const AFileName: string): Boolean;

function CreateRegEntity(const AGroup: string; const ID: Integer;
  const AConv: TsgDXFConverter; var AExtData: TsgCADExtendedData): TsgDXFEntity;
procedure RegisterEntityClass(const AGroup: string; const ID: Integer;
  const AClass: TClass);
procedure UnRegisterEntityClass(const AGroup: string; const ID: Integer);

procedure CopyEntitiesLnk(const ADest, ASource: TsgDXFEntity); overload;
procedure CopyEntitiesLnk(const ADest: TList;
  const ASource: TsgDXFEntity); overload;
procedure CopyEntitiesLnk(const ADest: TsgDXFEntity;
  const ASource: TList); overload;

function IsCADGradient(const AEntity: TsgDXFEntity): Boolean;
function IsEntity(const AEntity: TObject): Boolean;
function IsIncludeBlock(const Value1, Value2: Pointer): Boolean;
function IsIncludeStyle(const Value1, Value2: Pointer): Boolean;
function IsIncludeDimStyle(const Value1, Value2: Pointer): Boolean;
function IsIncludeAllDimesionStyle(const Value1, Value2: Pointer): Boolean;
function ReLoadEntities(const AImage: Pointer; const AChanged: TsgDXFEntity;
  const AProc: TsgProcEqual): TFRect;

procedure LinkDataBase(AConv: TsgDXFConverter);
procedure LoadDataBase(AConv: TsgDXFConverter);

procedure AddVertexList(const AList: TList; const APoint: TFPoint);
function AddVertexInList(const AList: TList; const APoint: TFPoint;
  const ABulge: Double = 0): TsgDXFVertex;
function AddVertexInPolyline(const APoly: TsgDXFPolyline; const APoint: TFPoint;
  const ABulge: Double = 0): TsgDXFVertex;
procedure AddVertesesInPolyline(const APoly: TsgDXFPolyline;
  const APoints: TList);
function CreateCADEllipticArc(const APoint, ARatPt1, ARatPt2: TFPoint;
  const APStart, APEnd: PFPoint): TsgDXFEllipse;

function FindByHandle(const AOwner: TsgDXFEntity; const AHandle: UInt64;
  var AIndex: Integer): Boolean; overload;
function FindByHandle(const AList: TList; const AHandle: UInt64;
  var AIndex: Integer): Boolean; overload;
function FindChildByEntName(const AOwner: TsgDXFEntity; const AName: string;
  const ACaseSensitive: Boolean; var AIndex: Integer): Boolean;

function GetOleExtents(AOleObject: IOleObject; ADrawAspect: Integer;
  out ASize: TPoint): Boolean;
function GetTransClipRect(const ALayout: TsgDXFLayout;
  const ADrawMatrix: TFMatrix; const AClipRectangle: PFRect): TFRect;
procedure SetArcParams(const Arc: TsgDXFArc; const AP1, AP2: TFPoint;
  const ABulge: Double);

function GetClassXDataProcs: TsgClassXDataProcs;
procedure SetClassXDataProcs(const AXDataProcs: TsgClassXDataProcs);

procedure DimStylePropsToHeadVarStruct(const ADimStyle: TsgDXFDimensionStyle;
  const AConv: TsgDXFConverter);

function CheckStandartNames(var AName: string): Boolean;
procedure SetProcFindFont(const P: TsgCADFindFont);

// Not documented, only for internal using (!)
procedure ReadProxyData(AProxyEntList, ASubEntPropsList: TList;
  AConv: TsgDXFConverter; AProxyReader: IProxyReader);
procedure FillSubDMesh(AMesh: TsgDXFEntity; AVerteces: TFPointList;
  AIndexes: TsgIntegerList);

var
  MacroStrings: TStringList;
  LoadEntityProc: TsgCADLoadEntitiy;
  GlobalCheckNameLayer: Boolean;

implementation

uses
{$IFNDEF SGFPC}
  OleCtnrs,
  AxCtrls,
{$ENDIF}
  ComObj,
  CADImage,
  sgBitmap,
  sgHatch,
  sgUnicode,
  sgSATBinToTextConv,
  sgBrepConverter,
  TTF
{$IFDEF SGABVIewer}
    , RasterFunctions
{$ENDIF}
  (*{$IFDEF DEMO}
    , Forms
    {$ELSE}
    {$IFDEF FRDEMO}
    , Forms
    {$ENDIF}
    {$ENDIF}*);

var
{$IFDEF SG_BTI}
  XDataProc__: TsgClassXDataProcs = nil;
{$ENDIF}
  GlobalFindFont: TsgCADFindFont = nil;
  XRefFileClasses: TStringList = nil;
  GlobalLoadingXRefsStack: TThreadList = nil;

procedure SetProcFindFont(const P: TsgCADFindFont);
begin
  GlobalFindFont := P;
end;

const
  cnstSectionsByFindObject: array [0 .. 12] of TConvSection = (csLayouts,
    csBlocks, csLTypes, csLayers, csStyles, csDimStyles, csBlockRecords,
    csVPorts, csMLineStyles, csTableStyles, csImageDefs, csObjects, csTables);

  wcDiametr: WCHAR = WCHAR($00D8);
  wcDiameterUni: WCHAR = WCHAR($2205);

  cnstDiameterUni = '\U+00D8';
  cnstDiameterArialUni = '\U+2205';
  cnstTextParseZero: TsgTextParse = ();
  cnstCoords = 3; // X, Y and Z - points dimension (for SPLINE)

type
  TsgSectionInfo = record
    Name: string;
    ClassType: TsgDXFEntityClass;
  end;

const
  cnstSectionNames: array [TConvSection] of TsgSectionInfo =
    ((Name: cnstSectionTABLES; ClassType: TsgDXFSectionTables),
    (Name: cnstSectionBLOCKS; ClassType: TsgDXFSectionBlocks),
    (Name: cnstSectionENTITIES; ClassType: TsgDXFBlock), (Name: cnstTableLTYPE;
    ClassType: TsgDXFTable), (Name: cnstTableLAYER; ClassType: TsgDXFTable),
    (Name: cnstTableSTYLE; ClassType: TsgDXFTable), (Name: cnstTableDIMSTYLE;
    ClassType: TsgDXFTable), (Name: cnstTableBLOCK_RECORD;
    ClassType: TsgDXFBlockRecords), (Name: cnstTableVPORT;
    ClassType: TsgDXFTable), (Name: cnstObjectsMLINESTYLES;
    ClassType: TsgDXFDictionary), (Name: cnstObjectsIMAGEDEFS;
    ClassType: TsgDXFDictionary), (Name: cnstObjectsLAYOUTS;
    ClassType: TsgDXFDictionary), (Name: cnstObjectsTABLESTYLES;
    ClassType: TsgDXFDictionary), (Name: cnstSectionOBJECTS;
    ClassType: TsgDXFSectionObjects));

  cnstAcExpr = 'AcExpr';
  cnstFormat2Digits = '\f';

type
  PsgRegClass = ^TsgRegClass;

  TsgRegClass = record
    RID: Integer;
    RClass: TClass;
  end;

  TsgCADImageAccess = class(TsgCADImage);
  TsgBitmapAccess = class(TsgBitMap);

  TsgCreatorSegments = class
  private
    FArrows: TFPointList;
    FCounts: TsgIntegerList;
    FDottedSingPts: TFPointList;
    FPoints: TFPointList;
    FPolyLine: TsgDXFLWPolyline;
    FPolyPoints: TFPointList;
    FPolyCounts: TsgIntegerList;
    FPolyExtrusion: PFPoint;
    FPointsIndex: Integer;
    FPointsCount: Integer;
    FIsPolylineClosed: Boolean;
    FIsPolyLineSolid: Boolean;
    FMakeCrossSegments: Boolean;
    FIsManyDottedPoints: Boolean;
    FStartWidth: Double;
    FSegmentSinCos: TFPoint;
    FSegmentLength: Double;
    FEndWidth: Double;
    FSegmentFirst: TsgIndexes4;
    FSegmentFirstLinear: Boolean;
    FSegmentLast: TsgIndexes4;
    FSegmentLastLinear: Boolean;
    FVertexCount: Integer;
    FVertexFirst: Integer;
    FMatrix: PFMatrix;
    procedure AddPFPoint(const APoint: PFPoint);
    procedure ClearPFPoints;
    function DistanceIndexes(const I1, I2: Integer): Double;
    function DistanceIndexesSqr(const I1, I2: Integer): Extended;
    function AddSegment(const APC, AP1, AP2: PFPoint; const AW1, AW2: Double)
      : TsgIndexes4;
    function GetCenterIndexes(const AIndexes: TsgIndexes4): TsgLine;
    function GetPolyPoint(AIndex: Integer): TFPoint;
    function GetSegment(const AP1, AP2, AD1, AD2: TFPoint): TsgPoints4;
    function GetSegmentLinear(const AP1, AP2: TFPoint; const AW1, AW2: Double)
      : TsgPoints4;
    function GetSegmentCircular(const APC, AP1, AP2: TFPoint;
      const AW1, AW2: Double): TsgPoints4;
    function GetVertex(const AIndex: Integer): TsgDXFVertex;
    function GetVertexesCount: Integer;
    function GetVertexFirst: Integer;
    function IsCrossIndexes(const I11, I12, I21, I22: Integer;
      const ACross: PFPoint): Boolean;
    function IsCorrectExtendedAngle(const APB, AP1, AP2: TFPoint): Boolean;
    function IsCorrectJoinAngle(const APB, AP1, AP2: TFPoint): Boolean;
    procedure SetActiveEdges(const AIsFirst: Boolean; const APts: TsgIndexes4;
      var AActPts: TsgIndexes4);
    procedure SetPFPoint2DValue(const AIndex: Integer; const AValue: TFPoint);
    function UseAsSolid: Boolean;
  protected
    procedure MakeSegments(const APoints: TFPointList; const ACenter: PFPoint);
    procedure LoadPointsAndCalcParams;
    procedure LoadPoinstBySegment(const AClosed: Boolean;
      const ACenter: PFPoint);
    procedure CheckGlobalWidth;
    procedure CrossingSegments(const AIsLinear1, AIsLinear2: Boolean;
      const APts1, APts2: TsgIndexes4);
    function GetPFPoint(const APoints: TFPointList;
      var AIndex: Integer): PFPoint;
    function GetStartAndEndWidths(const AVertex: TsgDXFVertex;
      var AStartWidth, AEndWidth: Double): Boolean;
    function IsNillWidth(const AVertex: TsgDXFVertex): Boolean;
    procedure ExtendSegments(const AIsFirstLine: Boolean;
      const APtsLine, APtsCircle: TsgIndexes4);
    procedure JoinSegments(const APts1, APts2: TsgIndexes4);
    property PolyPoints[AIndex: Integer]: TFPoint read GetPolyPoint;
    property Vertexes[const AIndex: Integer]: TsgDXFVertex read GetVertex;
    property VertexFirst: Integer read GetVertexFirst;
    property VertexesCount: Integer read GetVertexesCount;
  public
    constructor Create(const APolyline: TsgDXFLWPolyline;
      const ALines: TsgLines; const AMatrix: PFMatrix = nil);
    procedure LoadSegments(const AsSolid: Boolean = False);
    destructor Destroy; override;
  end;

  TsgMTextParser = class
  private
    FConverter: TsgDXFConverter;
    FDest: TsgDXFEntity;
    FDestWidth: Double;
    FFontParams: TsgFontParams;
    FHasLine: Boolean;
    FIndex: Integer;
    FLenByRow: Double;
    FLength: Integer;
    FLevels: TsgIntegerList;
    FListCarry: TList;
    FNeedSetupOptions: Boolean;
    FPos: TF2DPoint;
    FSource: TsgDXFMText;
    FString: string;
    FTextParse: TsgTextParse;
    function IsTextEmpty(const AText: TsgDXFText): Boolean;
    function IsFirstText(const AText: Pointer): Boolean;
    function GetBoxWidth(const AText: TsgDXFText): Double;
    function GetDestWidth: Double;
    function GetTextHeight(const AText: TsgDXFText): Double;
    function GetTextTab(const AText: TsgDXFText): Double;
    function GetTextWidth(const AText: Pointer): Double;
    procedure SetIsFirstTextAndLoad(const AText: TsgDXFText);
  protected
    FCells: TList;
    FCellColor: TsgColorCAD;
    FCellSize: Double;
    procedure CorrectTextByDivision;
    procedure CorrectTextByHyphenation;
    procedure CorrectTextByTolerance;
    procedure AdjustChildren;
    function CreateDefaultText: TsgDXFText;
    procedure CarryString(const AText: TsgDXFText);
    procedure CopyTextOptions(const ATextBase, AText: TsgDXFText);
    procedure DivisionString;
    procedure DivisionStringWithHyphenation;
    procedure LevelingString;
    function MakeFraction(const AText: TsgDXFText): Integer;
    procedure ReadParams(var AText: TsgDXFText);
    procedure SpliteTextbySpace(const AEntities: TsgDXFEntity; AStart: Integer);
  public
    constructor Create(const AConv: TsgDXFConverter);
    destructor Destroy; override;
    function Parse(const Source, Dest: TsgDXFEntity): Boolean;
  end;

  PCellBorderLineData = ^TCellBorderLineData;

  TCellBorderLineData = record
    ID: Integer;
    Cell: TsgAcadTableCell;
    Border: Integer;
    Span: Integer;
  end;

  TsgAcadTableGenerator = class
  private
    FAcadTable: TsgDXFAcadTable;
    FConv: TsgDXFConverter;
    FData: TList;
    FIndex: array [Boolean] of Integer;
    FRange: TRange;
    FSgn: array [Boolean] of Integer;
    function AddLineData(const AHorz: Boolean; const ACell: TsgAcadTableCell;
      const ABorder: Integer; const ASpan: Integer): PCellBorderLineData;
    function CreateMText(const ACell: TsgAcadTableCell;
      const ADoCreate, ALoad: Boolean): TsgDXFMText;
    procedure GenerateLines(const ALines: TList; const AHoresontal: Boolean);
    function GetCell(AHorz: Boolean; ADec: Integer): TsgAcadTableCell;
    function GetSizes(AHorz: Boolean): Double;
    function GetActiveCellBorderLineData(AHorz: Boolean): PCellBorderLineData;
  protected
    property Cell[AHorz: Boolean; ADec: Integer]: TsgAcadTableCell read GetCell;
    property Sizes[AHorz: Boolean]: Double read GetSizes;
    property ActiveCellBorderLineData[AHorz: Boolean]: PCellBorderLineData
      read GetActiveCellBorderLineData;
  public
    constructor Create(const AConv: TsgDXFConverter;
      const AAcadTable: TsgDXFAcadTable);
    constructor CreateRanged(const AConv: TsgDXFConverter;
      const AAcadTable: TsgDXFAcadTable; const ARange: TRect);
    destructor Destroy; override;
    function GenerateBlock: TsgDXFBlock;
    property Range: TRange read FRange;
  end;

  TListNotifyClearWrapper = class
  private
    FListNotify: TListNotify;
    FNotify: TsgObjProcListNotify;
    FDoFree: Boolean;
  protected
    procedure DoNotify(Ptr: Pointer; Action: TListNotification); dynamic;
    procedure ClearListNotify(Ptr: Pointer; Action: TListNotification); virtual;
  public
    constructor Create(const AListNotify: TListNotify; const ADoFree: Boolean);
    destructor Destroy; override;
    procedure Clear;
  end;

  TListNotifyClearWrapperGroup = class(TListNotifyClearWrapper)
  protected
    procedure ClearListNotify(Ptr: Pointer; Action: TListNotification);
      override;
  end;

  TsgImageDefPicture = class(TPicture)
  private
    FImageDef: TsgDXFImageDef;
  public
    constructor Create(AImageDef: TsgDXFImageDef); virtual;
    destructor Destroy; override;
    property ImageDef: TsgDXFImageDef read FImageDef;
  end;

  TsgStyleItem = class(TsgTableItem)
  private
    FNotifyChange: TNotifyEvent;
  protected
    procedure SetItem(const Value: TsgDXFEntity); override;
  public
    property NotifyChange: TNotifyEvent read FNotifyChange write FNotifyChange;
  end;

  TsgDictionaryItem = class(TsgTableItem)
  private
    FEntity: TsgDXFEntity;
  public
    constructor Create(AEntity: TsgDXFEntity); virtual;
    property Entity: TsgDXFEntity read FEntity;
  end;

var
  ExternalEntities: TsgStringList = nil;
  StdLines: TsgLines;
  // GlobalConvertersByOpenFromPicture: IsgCollectionPointer = nil;

procedure ClearEntCollection(AListNotify: TListNotify; ADoFree: Boolean);
var
  ListNotifyClearWrapper: TListNotifyClearWrapper;
begin
  ListNotifyClearWrapper := TListNotifyClearWrapper.Create(AListNotify,
    ADoFree);
  try
    ListNotifyClearWrapper.Clear;
  finally
    ListNotifyClearWrapper.Free;
  end;
end;

procedure ClearItemsCollection(AListNotify: TListNotify; ADoFree: Boolean);
var
  ListNotifyClearWrapper: TListNotifyClearWrapperGroup;
begin
  ListNotifyClearWrapper := TListNotifyClearWrapperGroup.Create
    (AListNotify, ADoFree);
  try
    ListNotifyClearWrapper.Clear;
  finally
    ListNotifyClearWrapper.Free;
  end;
end;

procedure SwapEntitiesHandle(const AEntity1, AEntity2: TsgDXFEntity);
var
  vTmp: UInt64;
begin
  vTmp := AEntity1.Handle;
  AEntity1.Handle := AEntity2.Handle;
  AEntity2.Handle := vTmp;
end;

procedure AddListPointsPolyline(const AList: TList;
  const APoly: TsgCADBasePolyline; const AClosing: Boolean;
  const AReversed: Boolean);
var
  I: Integer;
  vPoints: TList;
begin
  if APoly.PointCount > 0 then
  begin
    vPoints := TList.Create;
    AList.Add(vPoints);
    vPoints.Capacity := APoly.PointCount + 1;
    if AReversed then
      for I := APoly.PointCount - 1 downto 0 do
        AddFPointInList(vPoints, APoly.Points[I])
    else
      for I := 0 to APoly.PointCount - 1 do
        AddFPointInList(vPoints, APoly.Points[I]);
    if AClosing then
      AddFPointInList(vPoints, PFPoint(vPoints[0])^);
  end;
end;

function CheckEntTypeByRealod(const AEnt: TsgDXFEntity;
  const AReloadCircular: Boolean): Boolean;
begin
  Result := (AEnt is TsgCADCurvePolygon);
  if not Result then
  begin
    if AReloadCircular then
      Result := AEnt is TsgCADBasePolyline
    else
      Result := AEnt is TsgDXFSpline
  end;
end;

function GetTextContours(const AConverter: TsgDXFConverter;
  const AText: TsgDXFText; const AList: TList): Integer;
var
  I: Integer;
  vTextGlyph: TsgTextGlyph;
  vMatrix: TFMatrix;
begin
  Result := 0;
  if Assigned(AConverter) and Assigned(AText) then
  begin
    if AConverter.UseSHXFonts and (not AText.WinFont) then
    begin
      AText.GetSHXLinesEx(AConverter.SHXFonts, AList, nil, nil, nil,
        AConverter.CodePage);
      if AList.Count > 0 then
        Result := 1;
    end;
    if Result = 0 then
    begin
      I := ContainerOfTextGlyphs.IndexOf(AText.Font.Name,
        TFontStyles(AText.Font.Style));
      if I > -1 then
      begin
        Result := 2;
        vTextGlyph := ContainerOfTextGlyphs.TextGlyph[I];
        vMatrix := AText.GetMatrix;
        vTextGlyph.GetPolyPolylineW(AText.Text, AText.UnicodeText,
{$IFDEF SGFPC}Integer{$ELSE}Byte{$ENDIF}(AText.Font.Style), @vMatrix,
          AList, nil);
      end;
    end;
  end;
end;

function GetDimensionType(const AFlags: Integer): TsgDimensionType;
begin
  case AFlags and 7 of
    0:
      Result := dmtRotHorVert;
    1:
      Result := dmtAligned;
    2:
      Result := dmtAngular;
    3:
      Result := dmtDiameter;
    4:
      Result := dmtRadius;
    5:
      Result := dmtAngular3Point;
    6:
      Result := dmtOrdinate;
  else
    Result := dmtUndefined;
  end;
end;

{ CircleFromThreePoints
  Parameters:
  P1, P2, P3 - the circle points that form the triangle ABC
  (AB = [P1 P2], BC = [P2 P3], AC = [P3 P1]). }
function CircleFromThreePoints(APoly: TsgDXFPolyline; const P1, P2, P3: TFPoint;
  const APartsNumber: Integer; const AIsCircle: Boolean): Boolean;
const
  cnstZero = 1E-15;
var
  vDet: array [0 .. 2] of Double;
  vRadius, vSweepAngle, Tau, Phi, Delta: Double;
  vCenter, N, Nx, Ny, vOrtAB, vCenterAB, vCenterBC, vCenterAC, vP1,
    vP3: TFPoint;
  vVertex: TsgDXFVertex;
  I: Integer;
begin
  Result := False;
  try
    vOrtAB := Ort(MakeFPoint(P2.X - P1.X, P2.Y - P1.Y, P2.Z - P1.Z));
    // Normal to the plane of a circle: N = [AB x AC]
    N := Ort(sgFunction.Vector(vOrtAB, MakeFPoint(P3.X - P1.X, P3.Y - P1.Y,
      P3.Z - P1.Z)));
    // Perpendicular to AB side: Nx = [AB x N]
    Nx := Ort(sgFunction.Vector(vOrtAB, N));
    // Perpendicular to AC side: Ny = [AC x N]
    Ny := Ort(sgFunction.Vector(MakeFPoint(P3.X - P1.X, P3.Y - P1.Y,
      P3.Z - P1.Z), N));
    vCenterAB := MakeFPoint(0.5 * (P2.X + P1.X), 0.5 * (P2.Y + P1.Y),
      0.5 * (P2.Z + P1.Z));
    vCenterBC := MakeFPoint(0.5 * (P3.X + P2.X), 0.5 * (P3.Y + P2.Y),
      0.5 * (P3.Z + P2.Z));
    vCenterAC := MakeFPoint(0.5 * (P3.X + P1.X), 0.5 * (P3.Y + P1.Y),
      0.5 * (P3.Z + P1.Z));
    vDet[0] := Nx.Y * Ny.X - Nx.X * Ny.Y;
    vDet[1] := Nx.Z * Ny.X - Nx.X * Ny.Z;
    vDet[2] := Nx.Z * Ny.Y - Nx.Y * Ny.Z;
    if not IsRange(vDet[0], cnstZero) then
      Tau := (Ny.X * (vCenterAC.Y - vCenterAB.Y) - Ny.Y *
        (vCenterAC.X - vCenterAB.X)) / vDet[0]
      // Tau1 :=  (Nx.X*(vCenterAC.Y - vCenterAB.Y) - Nx.Y*(vCenterAC.X - vCenterAB.X))/vDet[0];
    else if not IsRange(vDet[1], cnstZero) then
      Tau := (Ny.X * (vCenterAC.Z - vCenterAB.Z) - Ny.Z *
        (vCenterAC.X - vCenterAB.X)) / vDet[1]
    else if not IsRange(vDet[2], cnstZero) then
      Tau := (Ny.Y * (vCenterAC.Z - vCenterAB.Z) - Ny.Z *
        (vCenterAC.Y - vCenterAB.Y)) / vDet[2]
    else
      Exit; // undefined Error
    vCenter := MakeFPoint(Nx.X * Tau + vCenterAB.X, Nx.Y * Tau + vCenterAB.Y,
      Nx.Z * Tau + vCenterAB.Z);
    vRadius := Sqrt(Sqr(P1.X - vCenter.X) + Sqr(P1.Y - vCenter.Y) +
      Sqr(P1.Z - vCenter.Z));
    if AIsCircle then
      vSweepAngle := 2 * Pi
    else
    begin
      Nx := Ort(MakeFPoint(P1.X - vCenter.X, P1.Y - vCenter.Y,
        P1.Z - vCenter.Z));
      vOrtAB := Ort(sgFunction.Vector(N, Nx));
      vP1 := Ort(MakeFPoint(P1.X - vCenter.X, P1.Y - vCenter.Y,
        P1.Z - vCenter.Z));
      vP3 := Ort(MakeFPoint(P3.X - vCenter.X, P3.Y - vCenter.Y,
        P3.Z - vCenter.Z));
      vSweepAngle := SGArcCos(vP1.X * vP3.X + vP1.Y * vP3.Y + vP1.Z * vP3.Z);
    end;
    Phi := 0;
    Delta := vSweepAngle / APartsNumber;
    for I := 0 to APartsNumber do
    begin
      vVertex := TsgDXFVertex.Create;
      vVertex.Point := MakeFPoint(vCenter.X + vRadius *
        (Nx.X * Cos(Phi) + vOrtAB.X * Sin(Phi)), vCenter.Y + vRadius *
        (Nx.Y * Cos(Phi) + vOrtAB.Y * Sin(Phi)), vCenter.Z + vRadius *
        (Nx.Z * Cos(Phi) + vOrtAB.Z * Sin(Phi)));
      APoly.AddEntity(vVertex);
      Phi := Phi + Delta;
    end;
  except
    Exit;
  end;
  Result := True;
end;

function ArcFromTwoVectors(APoly: TsgDXFPolyline;
  const ARadius, ASweepAngle: Double; const ACenter, ANormalVector,
  AStartVector: TFPoint; APartsNumber: Integer): Boolean;
var
  Phi, Delta: Double;
  vVertex: TsgDXFVertex;
  Ny: TFPoint;
  I: Integer;
begin
  Result := False;
  try
    Ny := Ort(sgFunction.Vector(ANormalVector, AStartVector));
    Phi := 0;
    Delta := ASweepAngle / APartsNumber;
    for I := 0 to APartsNumber do
    begin
      vVertex := TsgDXFVertex.Create;
      vVertex.Point := MakeFPoint(ACenter.X + ARadius *
        (AStartVector.X * Cos(Phi) + Ny.X * Sin(Phi)),
        ACenter.Y + ARadius * (AStartVector.Y * Cos(Phi) + Ny.Y * Sin(Phi)),
        ACenter.Z + ARadius * (AStartVector.Z * Cos(Phi) + Ny.Z * Sin(Phi)));
      APoly.AddEntity(vVertex);
      Phi := Phi + Delta;
    end;
  except
    Exit;
  end;
  Result := True;
end;

function IsFileOnWeb(const AFileName: string): Boolean;
const
  cHTTPprefx = 'http://';
  cWWWprefx = 'www.';
begin
  Result := (Pos(cHTTPprefx, AFileName) = 1) or (Pos(cWWWprefx, AFileName) = 1);
end;

function GetDimArrowTypeByDimSah(const DIMSAH: Boolean;
  const DIMBLK, DIMBLKx: TsgDimArrowType): TsgDimArrowType; overload;
begin
  if DIMSAH then
    Result := DIMBLKx
  else
    Result := DIMBLK;
end;

function GetDimArrowTypeByDimSah(const DIMSAH: Boolean;
  const InitDimBlk, InitDimBlkx: Boolean;
  const DIMBLK, DIMBLKx, DIMBLKSTYLE: TsgDimArrowType)
  : TsgDimArrowType; overload;
var
  vDimBlkx: TsgDimArrowType;
begin
  vDimBlkx := DIMBLKSTYLE;
  if InitDimBlkx then
  begin
    vDimBlkx := DIMBLKx;
    if (vDimBlkx = datClosedfilled) then
    begin
      if InitDimBlk then
        vDimBlkx := DIMBLK
      else
        vDimBlkx := DIMBLKSTYLE;
    end;
  end;
  Result := GetDimArrowTypeByDimSah(DIMSAH, DIMBLK, vDimBlkx);
end;

procedure SetDimArrowType1BySah(const Value: TsgDimArrowType;
  var ADim: TsgDimStyle);
begin
  if ADim.Sah then
  begin
    ADim.Arrows.Blk1 := Value;
    if ADim.Arrows.Blk1 = ADim.Arrows.Blk2 then
    begin
      ADim.Sah := False;
      ADim.Arrows.Blk := ADim.Arrows.Blk1;
    end;
  end
  else
  begin
    ADim.Arrows.Blk := Value;
    ADim.Arrows.Blk1 := Value;
    ADim.Arrows.Blk2 := Value;
  end;
end;

procedure SetDimArrowType2BySah(const Value: TsgDimArrowType;
  var ADim: TsgDimStyle);
begin
  if not ADim.Sah then
  begin
    ADim.Sah := True;
    ADim.Arrows.Blk1 := ADim.Arrows.Blk;
  end;
  ADim.Arrows.Blk2 := Value;
  if ADim.Arrows.Blk1 = ADim.Arrows.Blk2 then
  begin
    ADim.Sah := False;
    ADim.Arrows.Blk := ADim.Arrows.Blk1;
  end;
end;

function LoadPictureFromDisk(const APicture: TPicture;
  const AFileName: string): Boolean;
var
  vFileName: string;
begin
  vFileName := AFileName;
  if not FileExists(vFileName) then
    vFileName := ExtractFileName(AFileName);
  if FileExists(vFileName) then
    try
      APicture.LoadFromFile(vFileName)
    except
    end;
  Result := APicture.Graphic <> nil;
end;

function LoadPictureFromWEB(const APicture: TPicture;
  const AFileName: string): Boolean;
var
  vStream: TMemoryStream;
  vFileName: string;
  vProxyInfo: TsgHTTPProxyInfo;
  vReadFromWeb: Boolean;

  procedure InitProxyInfo;
  begin
    if cnstUseProxy then
      vProxyInfo := cnstProxyInfo
    else
    begin
      vProxyInfo.ProxyHost := '';
      vProxyInfo.ProxyPort := 0;
      vProxyInfo.ProxyNeedPass := False;
      vProxyInfo.ProxyUser := '';
      vProxyInfo.ProxyPass := '';
    end;
  end;

begin
  Result := False;
  vStream := TMemoryStream.Create;
  try
    vReadFromWeb := False;
    try
      InitProxyInfo;
      vReadFromWeb := GetDataFromHttp(AFileName, vStream, 60000 * 2, vFileName,
        cnstProxyInfo, cnstUseProxy);
    except
    end;
    if vReadFromWeb then
    begin
      try
        vFileName := GetTempDir + sTempFileName + vFileName;
        vStream.SaveToFile(vFileName);
        try
          Result := LoadPictureFromDisk(APicture, vFileName);
        finally
          DeleteFile(vFileName);
        end;
      except
        APicture.Graphic := nil;
      end;
    end;
  finally
    FreeAndNil(vStream);
  end;
end;

// Checks Converter1 > Converter2 [> ...] > Converter1
function CheckConverters(AGlobalConverters: IsgCollectionPointer;
  const AXrefPath: string): Boolean;
var
  I: Integer;
begin
  Result := True;
  if not((AGlobalConverters = nil) or (AGlobalConverters.Count = 0)) then
  begin
    I := AGlobalConverters.Count - 1;
    while (I >= 0) and Result do
      if TsgDXFConverter(AGlobalConverters[I]).FileName = ExtractFileName
        (AXrefPath) then
        Result := False
      else
        Dec(I);
  end;
end;

function CompareHandles(const AH1, AH2: UInt64): Integer;
begin
  // Result := AH1 - AH2;
  if AH1 = AH2 then
    Result := 0
  else if AH1 > AH2 then
    Result := 1
  else
    Result := -1;
end;

function CompareHandleEntities(const Ent1, Ent2: Pointer): Integer;
begin
  // Result := TsgDXFEntity(Ent1).Handle - TsgDXFEntity(Ent2).Handle;
  Result := CompareHandles(TsgDXFEntity(Ent1).Handle,
    TsgDXFEntity(Ent2).Handle);
end;

function CompareZDepthEntities(const Ent1, Ent2: Pointer): Integer;
var
  vInd: TsgFloat;
  vBox1, vBox2: TFRect;
begin
  vBox1 := TsgDXFEntity(Ent1).Box;
  vBox2 := TsgDXFEntity(Ent2).Box;
  vInd := (vBox1.Z1 + vBox1.Z2) - (vBox2.Z1 + vBox2.Z2);
  if vInd > fAccuracy then
    Result := 1
  else if vInd < -fAccuracy then
    Result := -1
  else
    Result := 0;
end;

function ComparePoint(AP1, AP2: PFPoint): Boolean;
begin
  Result := (not IsRange(AP1^.X - AP2^.X, fAccuracy)) or
    (not IsRange(AP1^.Y - AP2^.Y, fAccuracy)) or
    (not IsRange(AP1^.Z - AP2^.Z, fAccuracy)); // Return true if AP1 <> AP2;
end;

function ConvertDoubleToSingle(const ADouble: Double): Single;
begin
  if IsRange(ADouble, MaxSingle) then
    Result := ADouble
  else
    Result := (ADouble / Abs(ADouble)) * MaxSingle;
end;

procedure CreatesgBitMapBy1pxlDiv4(const BitMap: TsgBitMap; var BMP: TsgBitMap);
{$IFDEF SGABVIewer}
begin
  RasterFunctions.CreatesgBitMapLittle(TGraphic(BitMap), BMP, 4);
{$ELSE}
var
  vBitmap: Graphics.TBitmap;
  vMax, vW, vH: Integer;
begin
  vW := BitMap.Width div 4;
  vH := BitMap.Height div 4;
  vBitmap := Graphics.TBitmap.Create;
  try
    Inc(vW, Integer(vW = 0));
    Inc(vH, Integer(vH = 0));
    vBitmap.PixelFormat := BitMap.PixelFormat;
    vMax := MaxI(vW, vH);
    if vMax > cnstMaxImgSize then
    begin
      vW := cnstMaxImgSize * vW div vMax;
      vH := cnstMaxImgSize * vH div vMax;
    end;
    SetSizeBmp(vBitmap, vW, vH);
    SetStretchBltMode(vBitmap.Canvas.Handle, HALFTONE);
    vBitmap.Canvas.StretchDraw(Rect(0, 0, vBitmap.Width,
      vBitmap.Height), BitMap);
    BMP := TsgBitMap.Create;
    BMP.Assign(vBitmap);
  finally
    vBitmap.Free;
  end;
{$ENDIF}
end;

procedure CreatesgBitMapBy1pxlDiv8(const BitMap: TsgBitMap; var BMP: TsgBitMap);
{$IFDEF SGABVIewer}
begin
  RasterFunctions.CreatesgBitMapLittle(TGraphic(BitMap), BMP, 8);
{$ELSE}
var
  vBitmap: Graphics.TBitmap;
  vMax, vW, vH: Integer;
begin
  vW := BitMap.Width div 8;
  vH := BitMap.Height div 8;
  vBitmap := Graphics.TBitmap.Create;
  try
    Inc(vW, Integer(vW = 0));
    Inc(vH, Integer(vH = 0));
    vBitmap.PixelFormat := BitMap.PixelFormat;
    vMax := MaxI(vW, vH);
    if vMax > cnstMaxImgSize then
    begin
      vW := cnstMaxImgSize * vW div vMax;
      vH := cnstMaxImgSize * vH div vMax;
    end;
    SetSizeBmp(vBitmap, vW, vH);
    SetStretchBltMode(vBitmap.Canvas.Handle, HALFTONE);
    vBitmap.Canvas.StretchDraw(Rect(0, 0, vBitmap.Width,
      vBitmap.Height), BitMap);
    BMP := TsgBitMap.Create;
    BMP.Assign(vBitmap);
  finally
    vBitmap.Free;
  end;
{$ENDIF}
end;

procedure GenerateArrow(const AConverter: TsgDXFConverter;
  const ABlock: TsgDXFBlock; const ArrowType: TsgDimArrowType);

  procedure ApplyEntity(AEntity: TsgDXFEntity);
  begin
    AConverter.DoCreate(AEntity);
    ABlock.AddEntity(AEntity);
    AEntity.ColorCAD := cnstColorCADByBlock;
    AEntity.LineWeight := fLineWeightByBlock;
    AEntity.Loaded(AConverter);
  end;

  procedure AddArc(const CX, CY, ARadius, AStart, AEnd: Double);
  var
    vArc: TsgDXFArc;
  begin
    vArc := TsgDXFArc.Create;
    vArc.Point := MakeFPoint(CX, CY, 0);
    vArc.Radius := ARadius;
    vArc.StartAngle := AStart;
    vArc.EndAngle := AEnd;
    ApplyEntity(vArc);
  end;

  procedure AddCircle(const CX, CY, ARadius: Double);
  var
    vCircle: TsgDXFCircle;
  begin
    vCircle := TsgDXFCircle.Create;
    vCircle.Point := MakeFPoint(CX, CY, 0);
    vCircle.Radius := ARadius;
    ApplyEntity(vCircle);
  end;

  procedure AddLine(const X1, Y1, X2, Y2: Double);
  var
    vLine: TsgDXFLine;
  begin
    vLine := TsgDXFLine.Create;
    vLine.Point := MakeFPoint(X1, Y1, 0);
    vLine.Point1 := MakeFPoint(X2, Y2, 0);
    ApplyEntity(vLine);
  end;

  procedure AddLWPolyLine(const X1, Y1, B1, X2, Y2, B2, AGlobalW: Double);
  var
    vLWPolyline: TsgDXFLWPolyline;
    procedure Add2DVertex(const X, Y, ABulge: Double);
    var
      vVertex: TsgDXFVertex;
    begin
      vVertex := TsgDXFVertex.Create;
      vVertex.Point := MakeFPoint(X, Y, 0);
      vVertex.Bulge := ABulge;
      vLWPolyline.AddEntity(vVertex);
    end;

  begin
    vLWPolyline := TsgDXFLWPolyline.Create;
    vLWPolyline.Closed := True;
    vLWPolyline.GlobalWidth := AGlobalW;
    Add2DVertex(X1, Y1, B1);
    Add2DVertex(X2, Y2, B2);
    ApplyEntity(vLWPolyline);
  end;

  procedure AddSolid(const X1, Y1, X2, Y2, X3, Y3, X4, Y4: Double);
  var
    vSolid: TsgDXFSolid;
  begin
    vSolid := TsgDXFSolid.Create;
    vSolid.Point := MakeFPoint(X1, Y1, 0);
    vSolid.Point1 := MakeFPoint(X2, Y2, 0);
    vSolid.Point2 := MakeFPoint(X3, Y3, 0);
    vSolid.Point3 := MakeFPoint(X4, Y4, 0);
    ApplyEntity(vSolid);
  end;

begin
  case ArrowType of
    datClosedblank, datClosed: // '_CLOSEDBLANK', '_CLOSED'
      begin
        AddLine(-1, 1 / 6, 0, 0);
        AddLine(0, 0, -1, -1 / 6);
        AddLine(-1, 1 / 6, -1, -1 / 6);
        if ArrowType = datClosed then // '_CLOSED'
          AddLine(0, 0, -1, 0);
      end;
    datDot: // '_DOT'
      begin
        AddLWPolyLine(-0.25, 0, 1, 0.25, 0, 1, 0.5);
        AddLine(-0.5, 0, -1, 0);
      end;
    datArchtick: // '_ARCHTICK'
      AddLWPolyLine(-0.5, -0.5, 0, 0.5, 0.5, 0, 0.15);
    datOblique: // '_OBLIQUE'
      AddLine(-0.5, -0.5, 0.5, 0.5);
    datOpen: // '_OPEN'
      begin
        AddLine(-1, 1 / 6, 0, 0);
        AddLine(0, 0, -1, -1 / 6);
        AddLine(0, 0, -1, 0);
      end;
    datOrigin, datOrigin2, datDotblank: // '_ORIGIN', '_ORIGIN2', '_DOTBLANK'
      begin
        AddCircle(0, 0, 0.5);
        if ArrowType = datOrigin2 then
          AddCircle(0, 0, 0.25);
        if ArrowType = datOrigin then
          AddLine(0, 0, -1, 0)
        else
          AddLine(-0.5, 0, -1, 0);
      end;
    datOpen90: // '_OPEN90'
      begin
        AddLine(-0.5, 0.5, 0, 0);
        AddLine(0, 0, -0.5, -0.5);
        AddLine(0, 0, -1, 0);
      end;
    datOpen30: // '_OPEN30'
      begin
        AddLine(-1, 0.26794919, 0, 0);
        AddLine(0, 0, -1, -0.26794919);
        AddLine(0, 0, -1, 0);
      end;
    datDotsmall: // '_DOTSMALL'
      AddLWPolyLine(-0.0625, 0, 1, 0.0625, 0, 1, 0.5);
    datDotsmallbank: // '_DOTSMALLBLANK'
      AddCircle(0, 0, 0.25);
    datBoxblank: // '_BOXBLANK'
      begin
        AddLine(-0.5, -0.5, 0.5, -0.5);
        AddLine(0.5, -0.5, 0.5, 0.5);
        AddLine(0.5, 0.5, -0.5, 0.5);
        AddLine(-0.5, 0.5, -0.5, -0.5);
        AddLine(-0.5, 0, -1, 0);
      end;
    datBoxfilled: // '_BOXFILLED'
      begin
        AddSolid(-0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5);
        AddLine(-0.5, 0, -1, 0);
      end;
    datDatumblank: // '_DATUMBLANK'
      begin
        AddLine(0, 0.57735027, -1, 0);
        AddLine(-1, 0, 0, -0.57735027);
        AddLine(0, -0.57735027, 0, 0.57735027);
      end;
    datDatumfilled: // '_DATUMFILLED'
      AddSolid(0, 0.57735027, -1, 0, 0, -0.57735027, 0, -0.57735027);
    datIntegral: // '_INTEGRAL'
      begin
        AddArc(0.44488802, -0.09133463, 0.45416667, 102, 168);
        AddArc(-0.44488802, 0.09133463, 0.45416667, 282, 348);
      end;
    datNone: // '_NONE'
      begin
        { empty }
      end;
  else // _CLOSEDFILLED as default
    AddSolid(-1, 1 / 6, 0, 0, -1, 1 / 6, -1, -1 / 6);
    AddLine(-1, 0, -2, 0);
  end;
end;

function GetOleExtents(AOleObject: IOleObject; ADrawAspect: Integer;
  out ASize: TPoint): Boolean;
begin
  Result := False;
  if AOleObject <> nil then
  begin
    Result := AOleObject.GetExtent(ADrawAspect, ASize) = S_OK;
    if Result then
    begin
      ASize.X := MulDiv(ASize.X, GetDeviceCap(LOGPIXELSX), 2540);
      ASize.Y := MulDiv(ASize.Y, GetDeviceCap(LOGPIXELSY), 2540);
    end
  end
end;

function GetTransClipRect(const ALayout: TsgDXFLayout;
  const ADrawMatrix: TFMatrix; const AClipRectangle: PFRect): TFRect;
var
  vPictureRect: TFRect;
  vViewBox: TFRect;
begin
  FillChar(Result, SizeOf(Result), 0);
  vPictureRect := ALayout.Box;
  if Assigned(AClipRectangle) then
    vViewBox := AClipRectangle^
  else
    vViewBox := ALayout.Box;
  TransRectCorners(vPictureRect, ADrawMatrix);
  SwapDoubles(vPictureRect.Top, vPictureRect.Bottom);
  TransRectCorners(vViewBox, ADrawMatrix);
  SwapDoubles(vViewBox.Top, vViewBox.Bottom);
  Result.Left := (vViewBox.Left - vPictureRect.Left);
  Result.Top := vViewBox.Top - vPictureRect.Top;
  Result.Right := Result.Left + (vViewBox.Right - vViewBox.Left);
  Result.Bottom := Result.Top + (vViewBox.Bottom - vViewBox.Top);
end;

function GetVertex(AList: TList; Index: Integer; const ASy: Double)
  : PsgSHXVertex;
begin
  Result := nil;
  if Index < 0 then
    Exit;
  if Index >= AList.Count then
    Exit;
  Result := PsgSHXVertex(AList[Index]);
  Result^.X := Result^.X * ASy;
  Result^.Y := Result^.Y * ASy;
end;

function GetExportImageIndex(I: TsgDXFImageEnt; AIndex: Integer;
  ConverImageToOLE: Boolean): Integer;
begin
  if I.ImageDef <> nil then
    Result := cntImageExportAsImage
  else
  begin
    if AIndex = -1 then
      Result := cntImageExportAsOLE2Frame
    else
    begin
      if (sgMod(GetAngleByPoints(I.Point, I.Point1, False, fDoubleResolution, 1,
        1), 90) = 0) and
        (sgMod(GetAngleByPoints(I.Point, I.Point2, False, fDoubleResolution, 1,
        1), 90) = 0) and (ConverImageToOLE = True) then
        // no rotate image -> save to ole
        Result := cntImageExportAsOLE2Frame
      else
        Result := cntImageExportAsFile;
    end;
  end;
end;

function SGArcCos(const X: Double): Double;
begin
  Result := ArcTan2(Sqrt(Abs(1 - X * X)), X);
end;

function UnitRect: TFRect;
begin
  Result := MakeFRect(0, 1, 0, 1, 0, 0);
end;

function EntArc(E: TsgDXFArc; P: TsgCADIterate): TsgArc;
var
  R: TFRect;
  vP: TFPoint;
  C: TFPoint;

  procedure XP(X, Y: Extended);
  var
    Pt: TFPoint;
  begin
    Pt.X := C.X + X;
    Pt.Y := C.Y + Y;
    Pt.Z := C.Z;
    DoExtrusion(Pt, E.Extrusion);
    vP := FPointXMat(Pt, P.Matrix);
    ExpandFRect(R, TFPoint(vP));
    Pt.X := C.X - X;
    Pt.Y := C.Y - Y;
    Pt.Z := C.Z;
    DoExtrusion(Pt, E.Extrusion);
    vP := FPointXMat(Pt, P.Matrix);
    ExpandFRect(R, TFPoint(vP));
  end;

  function Angle(const Pt: TFPoint): Extended;
  begin
    Result := ArcTan2(Pt.Y - C.Y, Pt.X - C.X);
    if Result < 0 then
      Result := Result + Pi;
    if Pt.Y < C.Y then
      Result := Result + Pi;
  end;

begin
  Result.Valid := False;
  if (E.Extrusion.X <> 0) or (E.Extrusion.Y <> 0) or (E.Extrusion.Z <> 1.0) then
    Exit;
  R := BadRect;
  C := E.Point;
  if E is TsgDXFEllipse then
  begin
    if (E.EndPoint.X <> 0) and (E.EndPoint.Y <> 0) then
      Exit;
    XP(E.EndPoint.X, E.EndPoint.Y);
    XP(TsgDXFEllipse(E).Ratio * E.EndPoint.Y, TsgDXFEllipse(E).Ratio *
      E.EndPoint.X);
  end
  else
  begin
    XP(E.Radius, 0);
    XP(0, E.Radius);
  end;
  Result.Rect.TopLeft := R.TopLeft;
  Result.Rect.BottomRight := R.BottomRight;
  Result.Point1 := FPointXMat(E.PolyPoints[E.PolyPoints.Count - 1], P.Matrix);
  Result.Point2 := FPointXMat(E.PolyPoints[0], P.Matrix);
  DoScale2D(P);
  if P.XScale = 0 then // Polyline
    Exit;
  if (P.XScale < 0) xor (E.Extrusion.Z < 0) then
  begin
    vP := Result.Point2;
    Result.Point2 := Result.Point1;
    Result.Point1 := vP;
  end;

  Result.Center := FPointXMat(E.Point, P.Matrix);
  Result.Rx := Abs(Result.Rect.Right - Result.Rect.Left) / 2;
  Result.Ry := Abs(Result.Rect.Bottom - Result.Rect.Top) / 2;
  C := Result.Center;
  Result.Ang1 := Angle(Result.Point2); // End angle
  Result.Ang2 := Angle(Result.Point1); // Start angle
  Result.Valid := True;
end;

procedure ReadProxyData(AProxyEntList, ASubEntPropsList: TList;
  AConv: TsgDXFConverter; AProxyReader: IProxyReader);
var
  I, J, K, Count, vDataSize, vSubEntityType, vSubEntCount, vFact, vRowsNumber,
    vColumnsNumber, vEntriesNumber: Integer;
  vRadius, vSweepAngle: Double;
  vPTransform: PsgCADIterate;
  Pt1, Pt2, pt3: TFPoint;
  vPF2DPoint: TF2DPoint;
  vPSubProps: PsgSubProxyProps;
  vSymbol: Byte;
  vFill: Boolean;
  Str: string;
  vAStr: AnsiString;
  vTransforms: TList;
  vEntries: TsgIntegerList;
  vPolygon: TsgCADPolyPolygon;
  vPolyline: TsgDXFPolyline;
  vVertex: TsgDXFVertex;
  vText: TsgDXFText;
  vLine: TsgDXFLine;
  { vAng1, vAng2, vAng3, vAng4: Double;
    eLayerID, fLayerID, meshEdgesNumber, meshFacesNumber, vertNumber, rrr, epf, fpf, vpf: Integer;
    vPt: PFPoint;
    pp: TList; }

  function Read3RD: TFPoint;
  begin
    Result.X := AProxyReader.ReadDouble;
    Result.Y := AProxyReader.ReadDouble;
    Result.Z := AProxyReader.ReadDouble;
  end;

  function GetTextString: string;
  var
    WCh: Integer;
  begin
    Result := '';
    while True do // Reading text
    begin
      WCh := AProxyReader.ReadSmallInt;
      if WCh = 0 then
        Break;
      if (WCh shr 8 = 0) and CharInSet(Char(WCh), ['!' .. '~', ' ']) then
        Result := Result + Char(WCh)
      else
        Result := Result + '\U+' + IntToHex(WCh shr 8, 2) +
          IntToHex(WCh and $00FF, 2);
    end;
    SetLength(Result, Length(Result)); // to exclude special symbols
  end;

  function GetTransformPoint(const APoint: TFPoint): TFPoint;
  begin
    if vTransforms = nil then
      Result := APoint
    else
      Result := FPointXMat(APoint, PsgCADIterate(vTransforms.Last)^.Matrix);
  end;

  function GetTransformSize(const ASize: Double): Double;
  begin
    if vTransforms = nil then
      Result := ASize
    else
      Result := ASize * PsgCADIterate(vTransforms.Last)^.YScale;
  end;

  procedure InitSubProps; // first initialization
  begin
    New(vPSubProps);
    FillChar(vPSubProps^, SizeOf(vPSubProps^), 0);
    vPSubProps^.LayerIndex := -1;
    vPSubProps^.LTypeIndex := -1;
    vPSubProps^.ColorID := -1;
  end;

  procedure NewSubProps;
  var
    vTempPSubProps: PsgSubProxyProps;
  begin
    New(vTempPSubProps);
    CopyMemory(vTempPSubProps, vPSubProps, SizeOf(vTempPSubProps^));
    vPSubProps := vTempPSubProps;
  end;

  procedure AddEntityToProxy(AEntity: TsgDXFEntity);
  begin
    AProxyEntList.Add(AEntity);
    ASubEntPropsList.Add(vPSubProps);
    NewSubProps;
  end;

  function GetAngle(P, A: TFPoint): Single;
  var
    hip, leg: Double;
  begin
    Result := 0;
    if ((A.X > P.X) and (A.Y > P.Y)) then // quadrant 1
    begin
      hip := Sqrt(Sqr(A.X - P.X) + Sqr(A.Y - P.Y));
      leg := A.X - P.X;
      Result := (ArcCos(leg / hip) * f180DividedByPi);
      Exit;
    end
    else if ((A.X < P.X) and (A.Y > P.Y)) then // quadrant 2
    begin
      hip := Sqrt(Sqr(P.X - A.X) + Sqr(A.Y - P.Y));
      leg := P.X - A.X;
      Result := (180 - ArcCos(leg / hip) * f180DividedByPi);
      Exit;
    end
    else if ((A.X < P.X) and (A.Y < P.Y)) then // quadrant 3
    begin
      hip := Sqrt(Sqr(P.X - A.X) + Sqr(P.Y - A.Y));
      leg := P.X - A.X;
      Result := (180 + ArcCos(leg / hip) * f180DividedByPi);
      Exit;
    end
    else if ((A.X > P.X) and (A.Y < P.Y)) then // quadrant 4
    begin
      hip := Sqrt(Sqr(A.X - P.X) + Sqr(P.Y - A.Y));
      leg := A.X - P.X;
      Result := (360 - ArcCos(leg / hip) * f180DividedByPi);
      Exit;
    end
    else if ((A.Y = P.Y) and (A.X > P.X)) then
      Exit // Result := 0;
    else if ((A.Y > P.Y) and (A.X = P.X)) then
    begin
      Result := 90;
      Exit;
    end
    else if ((A.Y = P.Y) and (A.X < P.X)) then
    begin
      Result := 180;
      Exit;
    end
    else // if((a.Y < p.Y) and (a.X = p.X)) then
    begin
      Result := 270;
      Exit;
    end;
  end;

  procedure DoPolyline(const AClosed: Boolean);
  var
    N: Integer;
  begin
    Count := AProxyReader.ReadInteger;
    if Count = 2 then
    begin
      vLine := TsgDXFLine.Create;
      vLine.Point := GetTransformPoint(Read3RD);
      vLine.Point1 := GetTransformPoint(Read3RD);
      AddEntityToProxy(vLine);
    end
    else
    begin
      vPolyline := TsgDXFPolyline.Create;
      vPolyline.Polyline3D := True; // 3d Polyline
      for N := 0 to Count - 1 do
      begin
        vVertex := TsgDXFVertex.Create;
        vVertex.Point := GetTransformPoint(Read3RD);
        vPolyline.AddEntity(vVertex);
      end;
      vPolyline.Closed := AClosed;
      AddEntityToProxy(vPolyline);
    end;
  end;

  procedure SetSHXFont(const AText: TsgDXFText; const ASHXFont: string);
  // to be changed in the future versions
  begin
    AText.SetFontName(ASHXFont);
  end;

  function GetString(const AStr: AnsiString): string;
  begin
    Result := ConvertToWideString(AStr, AConv.CodePage);
  end;

  procedure Next(ASize: Integer);
  begin
    AProxyReader.PopPosition;
    AProxyReader.Seek(ASize);
  end;

begin
  AProxyReader.Seek(4); // seRL
  vSubEntCount := AProxyReader.ReadInteger;
  InitSubProps;
  vFill := False;
  vTransforms := nil;
  for I := 0 to vSubEntCount - 1 do
  begin
    vDataSize := AProxyReader.ReadInteger - 8;
    vSubEntityType := AProxyReader.ReadInteger;
    AProxyReader.PushPosition;
    case vSubEntityType of
      { 1:
        begin
        pt1 := Read3RD;
        pt2 := Read3RD;
        end; }
      2: // CIRCLE (normal circle)
        begin
          vPolyline := TsgDXFPolyline.Create;
          vPolyline.Polyline3D := True; // 3d Polyline
          Pt1 := GetTransformPoint(Read3RD);
          vRadius := AProxyReader.ReadDouble;
          Pt2 := Read3RD;
          // Definition of the start vector direction
          if (Pt2.X <= 1 + fAccuracy) and not IsEqual(Abs(Pt2.Y), 1.0) then
            pt3 := Ort(sgFunction.Vector(Pt2, cnstYOrtAxis))
          else
            pt3 := Ort(sgFunction.Vector(Pt2, cnstXOrtAxis));
          if ArcFromTwoVectors(vPolyline, vRadius, 2 * Pi, Pt1, Pt2, pt3,
            GetNumberOfCircleParts) then
            AddEntityToProxy(vPolyline)
          else
            vPolyline.Free;
        end;
      3: // CIRCLE3PT (3 point circle)
        begin
          vPolyline := TsgDXFPolyline.Create;
          vPolyline.Polyline3D := True; // 3d Polyline
          Pt1 := GetTransformPoint(Read3RD);
          Pt2 := GetTransformPoint(Read3RD);
          pt3 := GetTransformPoint(Read3RD);
          if CircleFromThreePoints(vPolyline, Pt1, Pt2, pt3,
            GetNumberOfCircleParts, True) then
            AddEntityToProxy(vPolyline)
          else
            vPolyline.Free;
        end;
      4: // CIRCULARARC (normal and start vector arc)
        begin
          vPolyline := TsgDXFPolyline.Create;
          vPolyline.Polyline3D := True; // 3d Polyline
          Pt1 := GetTransformPoint(Read3RD);
          vRadius := AProxyReader.ReadDouble;
          Pt2 := Read3RD;
          pt3 := Ort(Read3RD); // start vector direction
          vSweepAngle := AProxyReader.ReadDouble;
          AProxyReader.Seek(4); // seRL
          if ArcFromTwoVectors(vPolyline, vRadius, vSweepAngle, Pt1, Pt2, pt3,
            GetNumberOfCircleParts) then
            AddEntityToProxy(vPolyline)
          else
            vPolyline.Free;
        end;
      5: // CIRCULARARC3PT (3 point arc)
        begin
          vPolyline := TsgDXFPolyline.Create;
          vPolyline.Polyline3D := True; // 3d Polyline
          Pt1 := GetTransformPoint(Read3RD);
          Pt2 := GetTransformPoint(Read3RD);
          pt3 := GetTransformPoint(Read3RD);
          AProxyReader.Seek(4); // seRL
          if CircleFromThreePoints(vPolyline, Pt1, Pt2, pt3,
            GetNumberOfCircleParts, False) then
            AddEntityToProxy(vPolyline)
          else
            vPolyline.Free;
        end;
      6: // POLYLINE
        DoPolyline(False);
      7: // POLYGON
        begin
          if vFill then
          begin
            vPolygon := TsgCADPolyPolygon.Create;
            vPolygon.Boundaries.Add(TF2DPointList.Create);
            Count := AProxyReader.ReadInteger;
            for J := 0 to Count - 1 do
            begin
              Pt1 := GetTransformPoint(Read3RD);
              vPF2DPoint.X := Pt1.X;
              vPF2DPoint.Y := Pt1.Y;
              TF2DPointList(vPolygon.Boundaries[0]).Add(vPF2DPoint);
            end;
            AddEntityToProxy(vPolygon);
          end
          else
            DoPolyline(True);
        end;
      8: // MESH
        begin
          vPolyline := TsgDXFPolyline.Create;
          vRowsNumber := AProxyReader.ReadInteger;
          vColumnsNumber := AProxyReader.ReadInteger;
          for J := 0 to vRowsNumber - 1 do
            for K := 0 to vColumnsNumber - 1 do
            begin
              vVertex := TsgDXFVertex.Create;
              vVertex.Point := GetTransformPoint(Read3RD);
              vPolyline.AddEntity(vVertex);
            end;
          vPolyline.MeshM := vRowsNumber;
          vPolyline.MeshN := vColumnsNumber;
          AddEntityToProxy(vPolyline);
          Next(vDataSize); // if it is commented downwards
          { epf := AProxyReader.ReadInteger;
            if epf and $FFFF <> 0 then
            begin
            meshEdgesNumber := (vRowsNumber - 1) * vColumnsNumber +
            (vColumnsNumber - 1) * vRowsNumber;
            if epf and $00000001 <> 0 then
            for J := 0 to meshEdgesNumber - 1 do
            AProxyReader.ReadInteger;
            if epf and $00000002 <> 0 then
            for J := 0 to meshEdgesNumber - 1 do
            eLayerID := AProxyReader.ReadInteger;
            if epf and $00000004 <> 0 then
            for J := 0 to meshEdgesNumber - 1 do
            AProxyReader.ReadInteger;
            if epf and $00000020 <> 0 then
            for J := 0 to meshEdgesNumber - 1 do
            AProxyReader.ReadInteger;
            if epf and $00000040 <> 0 then
            for J := 0 to meshEdgesNumber - 1 do
            K := AProxyReader.ReadInteger;// visibility
            end;
            fpf := AProxyReader.ReadInteger;
            if fpf and $FFFF <> 0 then
            begin
            meshFacesNumber := (vRowsNumber - 1) * (vColumnsNumber - 1);
            if fpf and $00000001 <> 0 then
            for J := 0 to meshFacesNumber - 1 do
            AProxyReader.ReadInteger;
            if fpf and $00000002 <> 0 then
            for J := 0 to meshFacesNumber - 1 do
            fLayerID := AProxyReader.ReadInteger;
            if fpf and $00000020 <> 0 then
            for J := 0 to meshFacesNumber - 1 do
            AProxyReader.ReadInteger;
            if fpf and $00000080 <> 0 then
            for J := 0 to meshFacesNumber - 1 do
            pt1 := Read3RD;
            if fpf and $00000040 <> 0 then
            for J := 0 to meshFacesNumber - 1 do
            AProxyReader.ReadInteger;
            end;
            vpf := AProxyReader.ReadInteger;
            if vpf and $FFFF <> 0 then
            begin
            vertNumber := vRowsNumber * vColumnsNumber;
            if vpf and $00000080 <> 0 then
            for J := 0 to vertNumber - 1 do
            pt1 := Read3RD;
            if vpf and $00000400 <> 0 then
            AProxyReader.ReadInteger;
            end; }
        end;
      9: // SHELL
        begin
          vPolyline := TsgDXFPolyline.Create;
          vPolyline.Flags := 64;
          Count := AProxyReader.ReadInteger;
          for J := 0 to Count - 1 do
          begin
            vVertex := TsgDXFVertex.Create;
            vVertex.Point := GetTransformPoint(Read3RD);
            vPolyline.AddEntity(vVertex);
          end;
          vPolyline.MeshM := Count;
          vPolyline.MeshN := 1; // only for correct TsgDXFPolyline loading
          vEntriesNumber := AProxyReader.ReadInteger;
          vEntries := TsgIntegerList.Create;
          try
            for J := 0 to vEntriesNumber - 1 do
              vEntries.Add(AProxyReader.ReadInteger);
            J := 0;
            while J < vEntriesNumber do
            begin
              vVertex := TsgDXFVertex.Create;
              vVertex.Flags := 128;
              K := vEntries[J];
              for vFact := 1 to K do
                case vFact of
                  1:
                    vVertex.PolyFaceVertexIndex1 := vEntries[J + vFact] + 1;
                  2:
                    vVertex.PolyFaceVertexIndex2 := vEntries[J + vFact] + 1;
                  3:
                    vVertex.PolyFaceVertexIndex3 := vEntries[J + vFact] + 1;
                  4:
                    vVertex.PolyFaceVertexIndex4 := vEntries[J + vFact] + 1;
                else
                  // ERROR number
                end;
              Inc(J, K + 1);
              vPolyline.AddEntity(vVertex);
            end;
          finally
            vEntries.Free;
          end;
          AddEntityToProxy(vPolyline);
          Next(vDataSize); // if it is commented downwards
          { meshEdgesNumber := vEntriesNumber - 1;
            meshFacesNumber := Integer(vEntries[0]);
            epf := AProxyReader.ReadInteger;
            if epf and $0000FFFF <> 0 then
            begin
            if epf and $00000001 <> 0 then
            for J := 0 to meshEdgesNumber - 1 do
            rrr := AProxyReader.ReadInteger;
            if epf and $00000002 <> 0 then
            for J := 0 to meshEdgesNumber - 1 do
            eLayerID := AProxyReader.ReadInteger;
            if epf and $00000004 <> 0 then
            for J := 0 to meshEdgesNumber - 1 do
            rrr := AProxyReader.ReadInteger;
            if epf and $00000020 <> 0 then
            for J := 0 to meshEdgesNumber - 1 do
            rrr := AProxyReader.ReadInteger;
            if epf and $00000040 <> 0 then
            for J := 0 to meshEdgesNumber - 1 do
            rrr := AProxyReader.ReadInteger;
            end;
            fpf := AProxyReader.ReadInteger;
            if fpf and $0000FFFF <> 0 then
            begin
            if fpf and $00000001 <> 0 then
            for J := 0 to meshFacesNumber - 1 do
            rrr := AProxyReader.ReadInteger;
            if fpf and $00000002 <> 0 then
            for J := 0 to meshFacesNumber - 1 do
            fLayerID := AProxyReader.ReadInteger;
            if fpf and $00000020 <> 0 then
            for J := 0 to meshFacesNumber - 1 do
            rrr := AProxyReader.ReadInteger;
            if fpf and $00000080 <> 0 then
            for J := 0 to meshFacesNumber - 1 do
            pt1 := Read3RD;
            if fpf and $00000040 <> 0 then
            for J := 0 to meshFacesNumber - 1 do
            rrr := AProxyReader.ReadInteger;
            end;
            vpf := AProxyReader.ReadInteger;
            if vpf and $0000FFFF <> 0 then
            begin
            if vpf and $00000080 <> 0 then
            for J := 0 to Count - 1 do
            pt1 := Read3RD;
            if vpf and $00000400 <> 0 then
            rrr := AProxyReader.ReadInteger;
            end; }
        end;
      { 10:
        begin
        vText := TsgDXFText.Create;
        vText.Point := GetTransformPoint(Read3RD);
        vText.Extrusion := Read3RD;
        vText.Rotation := GetAngle(cnstFPointZero, Read3RD);
        vText.Height := AProxyReader.ReadDouble;
        vText.Scale := AProxyReader.ReadDouble;
        vText.ObliqueAngle := AProxyReader.ReadDouble;
        vAStr := AProxyReader.ReadAnsiPadding;
        Str := GetString(vAStr);
        vText.Text := Str;
        Next(vDataSize);
        AddEntityToProxy(vText);
        end; }
      11:
        begin
          vText := TsgDXFText.Create;
          vText.Point := GetTransformPoint(Read3RD);
          vText.Extrusion := Read3RD;
          vText.Rotation := GetAngle(cnstFPointZero, Read3RD); // Read3RD!
          vAStr := AProxyReader.ReadAnsiPadding;
          Count := AProxyReader.ReadInteger; // Text length
          if Count <> -1 then
            SetLength(vAStr, Count);
          Str := GetString(vAStr);
          vText.Text := Str;
          AProxyReader.Seek(4); // seRL
          vText.Height := GetTransformSize(AProxyReader.ReadDouble);
          vText.Scale := AProxyReader.ReadDouble;
          vText.ObliqueAngle := AProxyReader.ReadDouble * f180DividedByPi;
          vText.Rotation := GetAngle(cnstFPointZero, Read3RD) + vText.Rotation;
          // Read3RD!
          AProxyReader.Seek(4); // seRL
          vAStr := AProxyReader.ReadAnsiPadding;
          AProxyReader.Seek(4); // seRL
          Str := GetString(vAStr);
          SetSHXFont(vText, Str); // to be changed in the future versions
          Next(vDataSize);
          AddEntityToProxy(vText);
        end;
      { 12:
        begin
        pt1 := Read3RD;
        pt2 := Read3RD;
        end;
        13:
        begin
        pt1 := Read3RD;
        pt2 := Read3RD;
        end; }
      14:
        vPSubProps^.ColorID := AProxyReader.ReadInteger;
      16:
        vPSubProps^.LayerIndex := AProxyReader.ReadInteger;
      18:
        begin
          vPSubProps^.LTypeIndex := AProxyReader.ReadInteger;
          case vPSubProps^.LTypeIndex of
            $7FFF:
              vPSubProps^.LTypeIndex := -1;
            $7FFE:
              vPSubProps^.LTypeIndex := -2;
          end;
        end;
      19:
        vPSubProps^.Marker := AProxyReader.ReadInteger;
      20: // FILL (on/off)
        vFill := AProxyReader.ReadInteger = 1;
      22:
        begin
          vPSubProps^.ColorID := AProxyReader.ReadByte;
          AProxyReader.Seek(3); // seRC,seRC,seRC
        end;
      23:
        vPSubProps^.LWeight := AProxyReader.ReadInteger;
      24:
        vPSubProps^.LTScale := AProxyReader.ReadDouble;
      26:
        begin
          vPSubProps^.ProxyType := AProxyReader.ReadInteger;
          vPSubProps^.PlotStyleIndex := AProxyReader.ReadInteger;
        end;
      { 27:
        begin
        pt1 := Read3RD;
        pt2 := Read3RD;
        AProxyReader.ReadInteger;
        AProxyReader.ReadDouble;
        AProxyReader.ReadDouble;
        for J := 0 to 15 do
        AProxyReader.ReadDouble;
        for J := 0 to 15 do
        AProxyReader.ReadDouble;
        AProxyReader.ReadInteger;
        AProxyReader.ReadInteger;
        AProxyReader.ReadDouble;
        AProxyReader.ReadDouble;
        AProxyReader.ReadInteger;
        end; }
      29: // PUSH_MODELXFORM
        begin
          if vTransforms = nil then
            vTransforms := TList.Create;
          New(vPTransform);
          FillChar(vPTransform^, SizeOf(vPTransform^), 0);
          for J := 0 to 2 do
            for K := 0 to 3 do
              vPTransform^.Matrix.M[K, J] := AProxyReader.ReadDouble;
          if vTransforms.Count > 0 then
            vPTransform^.Matrix := FMatXMat(vPTransform^.Matrix,
              PsgCADIterate(vTransforms.Last)^.Matrix);
          DoScale2D(vPTransform^);
          vTransforms.Add(vPTransform);
          AProxyReader.Seek(32); // Inc2(APBit, 256);
        end;
      { 30:
        for J := 0 to 15 do
        AProxyReader.ReadDouble; }
      31: // POP_MODELXFORM
        if vTransforms <> nil then
        begin
          if vTransforms.Count > 0 then
          begin
            Dispose(vTransforms.Last);
            vTransforms.Delete(vTransforms.Count - 1);
          end;
          if vTransforms.Count = 0 then
            FreeRecordList(vTransforms);
        end;
      32: // ACAD_TABLE line (not documented)
        begin
          DoPolyline(False);
          AProxyReader.Seek(24); // se3RD
        end;
      { 34:
        begin
        AProxyReader.ReadInteger;
        AProxyReader.ReadInteger;
        end; }
      36: // AEC undocumented data
        begin
          vText := TsgDXFText.Create;
          vText.Point := GetTransformPoint(Read3RD);
          vText.Extrusion := Read3RD;
          vText.Rotation := GetAngle(cnstFPointZero, Read3RD); // Read3RD!
          vText.Height := GetTransformSize(AProxyReader.ReadDouble);
          vText.Scale := AProxyReader.ReadDouble;
          vText.ObliqueAngle := AProxyReader.ReadDouble * f180DividedByPi;
          vText.Text := GetTextString;
          // ... unknow data ...
          Next(vDataSize);
          AddEntityToProxy(vText);
        end;
      38: // ACAD_TABLE text (not documented)
        begin
          vText := TsgDXFText.Create;
          vText.Point := GetTransformPoint(Read3RD);
          vText.Extrusion := Read3RD;
          vText.Rotation := GetAngle(cnstFPointZero, Read3RD); // Read3RD!
          vText.Text := GetTextString;
          AProxyReader.Seek(4); // seRL
          vFact := AProxyReader.ReadInteger;
          if vFact > 1 then
            AProxyReader.Seek(2); // seRS
          // AProxyReader.ReadSmallInt;
          vText.Height := GetTransformSize(AProxyReader.ReadDouble);
          vText.Scale := AProxyReader.ReadDouble;
          vText.ObliqueAngle := AProxyReader.ReadDouble * f180DividedByPi;
          vText.Rotation := GetAngle(cnstFPointZero, Read3RD) + vText.Rotation;
          // Read3RD!
          AProxyReader.Seek(24); // seRL,seRL,seRL,seRL,seRL,seRL
          Str := '';
          while True do // Reading font name
          begin
            vSymbol := AProxyReader.ReadSmallInt;
            if (vSymbol = 0) then
              Break;
            Str := Str + string(AnsiChar(vSymbol));
          end;
          SetSHXFont(vText, Str); // to be changed in the future versions
          Next(vDataSize);
          AddEntityToProxy(vText);
        end;
    else
      Next(vDataSize); // Inc2(APBit, (vDataSize - 8) shl 3);
    end;
  end;
  FreeRecordList(vTransforms);
  Dispose(vPSubProps);
end;

procedure FillSubDMesh(AMesh: TsgDXFEntity; AVerteces: TFPointList;
  AIndexes: TsgIntegerList);
var
  I, J, vCountVertexFace: Integer;
  vFace: TsgDXF3dFace;
begin
  I := 0;
  while I < AIndexes.Count do
  begin
    vCountVertexFace := AIndexes[I];
    Inc(I);
    vFace := TsgDXF3dFace.Create;
    vFace.Flags := $10;

    for J := 0 to vCountVertexFace - 1 do
    begin
      case J of
        0:
          vFace.Point := AVerteces[AIndexes[I]];
        1:
          vFace.Point1 := AVerteces[AIndexes[I]];
        2:
          vFace.Point2 := AVerteces[AIndexes[I]];
        3:
          vFace.Point3 := AVerteces[AIndexes[I]];
      end;
      Inc(I)
    end;

    if vCountVertexFace = 3 then
      vFace.Point3 := vFace.Point2;

    vFace.ColorCAD := AMesh.ColorCAD;
    vFace.LineType := AMesh.LineType;
    vFace.Layer := AMesh.Layer;

    AMesh.AddEntity(vFace);
  end;
end;

procedure LinkDataBase(AConv: TsgDXFConverter);
var
  I: Integer;
  E: TsgDXFEntity;
{$IFDEF SG_BTI}
  vXDataProcs: TsgXDataProcs;
{$ENDIF}
  procedure LinkTable(const AEnt: TsgDXFEntity; const AConv: TsgDXFConverter);
  var
    K, L: Integer;
  begin
    if Assigned(AEnt) then
    begin
      for K := 0 to AEnt.Count - 1 do
      begin
        for L := 0 to AEnt[K].Count - 1 do
          AEnt[K][L].Link(AConv);
        AEnt[K].Link(AConv);
      end;
      AEnt.Link(AConv);
    end;
  end;

  procedure DoLink(const AEnt: TsgDXFEntity; const AConv: TsgDXFConverter);
  begin
{$IFDEF SG_BTI}
    if (vXDataProcs <> nil) and (AEnt.EntClass.EG = gtBTI) then
      vXDataProcs.LinkEntity(AEnt)
    else
{$ENDIF}
      AEnt.Link(AConv);
  end;

  procedure LinkEntity(const AEnt: TsgDXFEntity; const AConv: TsgDXFConverter
{$IFDEF SG_BTI}; const AMode: Integer = -1{$ENDIF});
  var
    K: Integer;
    vEnt: TsgDXFEntity;
  begin
    for K := 0 to AEnt.Count - 1 do
    begin
      vEnt := AEnt[K];
{$IFDEF SG_BTI}
      case AMode of
        0:
          begin
            if vEnt.EntClass.EG <> gtBTI then
              LinkEntity(vEnt, AConv);
          end;
        1:
          begin
            if vEnt.EntClass.EG = gtBTI then
              LinkEntity(vEnt, AConv);
          end;
      else
{$ENDIF}
        LinkEntity(vEnt, AConv);
{$IFDEF SG_BTI}
      end;
{$ENDIF}
    end;
    DoLink(AEnt, AConv);
  end;

begin
{$IFDEF SG_BTI}
  vXDataProcs := AConv.XDataProcs;
{$ENDIF}
  DoLink(AConv.Main, AConv);
  E := AConv.Main.FindEntByName(cnstSectionHEADER);
  if Assigned(E) then
    DoLink(E, AConv);
  // link tables
  LinkTable(AConv.Sections[csStyles], AConv);
  LinkTable(AConv.Sections[csLTypes], AConv);
  AConv.Sections[csLTypes].SortEntByHandle;
  LinkTable(AConv.Sections[csLayers], AConv);
  AConv.Sections[csLayers].SortEntByHandle;
  LinkTable(AConv.Sections[csDimStyles], AConv);
  LinkTable(AConv.Sections[csBlockRecords], AConv);

  // link objects
  for I := 0 to AConv.Counts[csObjects] - 1 do
    if AConv.Sections[csObjects][I] <> AConv.Sections[csLayouts] then
      LinkEntity(AConv.Sections[csObjects][I], AConv)
    else
      LinkTable(AConv.Sections[csObjects][I], AConv); // do not link papers

  // link blocks
{$IFDEF SG_BTI}
  LinkEntity(AConv.Sections[csBlocks], AConv, 1);
  LinkEntity(AConv.Sections[csBlocks], AConv, 0);
{$ELSE}
  LinkEntity(AConv.Sections[csBlocks], AConv);
{$ENDIF}
end;

type
  TLoader = class
  private
{$IFDEF SG_BTI}
    FXDataProcs: TsgXDataProcs;
{$ENDIF}
    FConv: TsgDXFConverter;
    FBlocks: TsgList;
  protected
    function LoadBlock(Entity: TsgDXFEntity): Integer;
  public
    constructor Create;
    destructor Destroy; override;
  end;

constructor TLoader.Create;
begin
  FBlocks := TsgList.Create;
  FBlocks.Duplicates := dupIgnore;
  FBlocks.Sorted := True;
end;

destructor TLoader.Destroy;
begin
  FBlocks.Free;
  inherited Destroy;
end;

function TLoader.LoadBlock(Entity: TsgDXFEntity): Integer;

  procedure DoLoad(const AEnt: TsgDXFEntity; const AConv: TsgDXFConverter);
  begin
{$IFDEF SG_BTI}
    if (FXDataProcs <> nil) and (AEnt.EntClass.EG = gtBTI) then
      FXDataProcs.LoadEntity(AEnt)
    else
{$ENDIF}
      AConv.Loads(AEnt);
  end;

  function LoadEntity(const AEnt: TsgDXFEntity;
    const AConv: TsgDXFConverter): Boolean;
  var
    K: Integer;
  begin
    for K := 0 to AEnt.Count - 1 do
      LoadEntity(AEnt[K], AConv);
    DoLoad(AEnt, AConv);
    Result := True;
  end;

begin
  if FBlocks.IndexOf(Entity) < 0 then
  begin
    FBlocks.Add(Entity);
    try
      LoadEntity(Entity, FConv);
    finally
      FBlocks.Remove(Entity);
    end;
  end;
  Result := 0;
end;

procedure LoadDataBase(AConv: TsgDXFConverter);
var
  I: Integer;
  vBlock: TsgDXFBlock;
  Loader: TLoader;
{$IFDEF SG_BTI}
  vXDataProcs: TsgXDataProcs;
{$ENDIF}
  procedure LoadTable(ATable: TsgDXFEntity; AConv: TsgDXFConverter);
  var
    K: Integer;
  begin
    if Assigned(ATable) then
      for K := 0 to ATable.Count - 1 do
        AConv.Loads(ATable[K]);
  end;

  procedure DoLoad(const AEnt: TsgDXFEntity; const AConv: TsgDXFConverter);
  begin
{$IFDEF SG_BTI}
    if (vXDataProcs <> nil) and (AEnt.EntClass.EG = gtBTI) then
      vXDataProcs.LoadEntity(AEnt)
    else
{$ENDIF}
      AConv.Loads(AEnt);
  end;

  function LoadEntity(const AEnt: TsgDXFEntity;
    const AConv: TsgDXFConverter): Boolean;
  var
    K: Integer;
  begin
    for K := 0 to AEnt.Count - 1 do
      LoadEntity(AEnt[K], AConv);
    DoLoad(AEnt, AConv);
    Result := True;
  end;

begin
  AConv.Status := stDefault;
{$IFDEF SG_BTI}
  vXDataProcs := AConv.XDataProcs;
{$ENDIF}
  LoadTable(AConv.Sections[csStyles], AConv);
  LoadTable(AConv.Sections[csLTypes], AConv);
  LoadTable(AConv.Sections[csLayers], AConv);
  LoadTable(AConv.Sections[csDimStyles], AConv);

  for I := 0 to AConv.Counts[csObjects] - 1 do
    if AConv.Sections[csObjects][I] <> AConv.Sections[csLayouts] then
      LoadEntity(AConv.Sections[csObjects][I], AConv);

  Loader := TLoader.Create;
  Loader.FConv := AConv;
  AConv.OnLoad := Loader.LoadBlock;
{$IFDEF SG_BTI}
  Loader.FXDataProcs := vXDataProcs;
{$ENDIF}
  for I := 0 to AConv.Counts[csBlocks] - 1 do
  begin
    vBlock := TsgDXFBlock(AConv.Sections[csBlocks][I]);
    if not Assigned(vBlock.Layout) then
    begin
      // for J := 0 to vBlock.Count - 1 do

      // {$IFDEF SG_BTI}
      // if (vXDataProcs <> nil) and (vBlock[J].EntClass.EG = gtBTI) then
      // vXDataProcs.LoadEntity(vBlock[J])
      // else
      // {$ENDIF}
      // LoadEntity(vBlock[J], AConv);

      Loader.LoadBlock(vBlock);
    end;
  end;
{$IFDEF SG_BTI}
  if Assigned(vXDataProcs) then
    vXDataProcs.Finalize;
{$ENDIF}
  for I := 0 to AConv.LayoutsCount - 1 do
    LoadEntity(AConv.Layouts[I].PaperSpaceBlock, AConv);
  for I := 0 to AConv.LayoutsCount - 1 do
    AConv.Loads(AConv.Layouts[I]);
  AConv.OnLoad := nil;
  Loader.Free;
end;

{ All operations with colors }
{$IFNDEF EVG}

function EntColor(E: TsgDXFEntity; Ins: TsgDXFInsert): TColor;
var
  vIns: TsgDXFInsert;
  vLayer, vInsLayer: TsgDXFLayer;
begin
  Result := E.Color;
  vIns := Ins;
  if Result < 0 then
    Result := clNone;
  vLayer := EntLayer(E, Ins);
  if vLayer = nil then
    Exit;
  if (Result = clByLayer) and (vLayer.Name <> '0') then
    Result := vLayer.Pen.Color;
  if (Result = clByLayer) or (Result = clByBlock) then
  begin
    if (vIns = nil) or ((Result = clByLayer) and (vLayer.Name <> '0')) then
    begin
      if Result = clByLayer then
        Result := vLayer.Pen.Color;
    end
    else
    begin
      vInsLayer := nil;
      while vIns <> nil do
      begin
        if Result = clByBlock then
          Result := vIns.Color;
        vInsLayer := EntLayer(vIns, nil);
        if (Result = clByLayer) and (vInsLayer.Name <> '0') then
          Result := vInsLayer.Pen.Color;
        if not((Result = clByBlock) or (Result = clByLayer)) then
          Break;
        vIns := vIns.Owner;
      end;
      if (vInsLayer <> nil) and (Result = clByLayer) then
        Result := vInsLayer.Pen.Color;
    end;
  end;
  if (Result = clByLayer) then
    Result := vLayer.Pen.Color;
  // I should be Layer.name = '0' and Entity.color = ByLayer!
  if (Result = clByBlock) or (Result = clByLayer) then
    Result := clNone;
end;
{$ELSE}

function EntColor(E: TsgDXFEntity; Ins: TsgDXFInsert): TColor;
var
  vIns: TsgDXFInsert;
  vLayer, vInsLayer: TsgDXFLayer;

  function IsAlfaChannelCanBe(AColor: TColor): Boolean;
  begin
    Result := (AColor < 0) and (AColor <> clByBlock) and (AColor <> clByLayer)
      and (AColor <> clEmpty);
  end;

begin
  vLayer := nil;
  Result := E.Color;
  vIns := Ins;
  if (Result < 0) and (not IsAlfaChannelCanBe(Result)) then
    Result := clNone;
  if (vIns <> nil) and ((Result = clByLayer) or (Result = clByBlock)) then
  // evg speed up !!! check for xrefs!!!
  begin
    vLayer := EntLayer(E, Ins);
    if vLayer = nil then
      Exit;
    if (Result = clByLayer) and (vLayer.Name <> '0') then
      Result := vLayer.Color;
    if (Result = clByLayer) or (Result = clByBlock) then
    begin
      if (vIns = nil) or ((Result = clByLayer) and (vLayer.Name <> '0')) then
      begin
        if Result = clByLayer then
          Result := vLayer.Color;
      end
      else
      begin
        vInsLayer := nil;
        while vIns <> nil do
        begin
          if Result = clByBlock then
            Result := vIns.Color;
          vInsLayer := EntLayer(vIns, nil);
          if (Result = clByLayer) and (vInsLayer.Name <> '0') then
            Result := vInsLayer.Color;
          if not((Result = clByBlock) or (Result = clByLayer)) then
            Break;
          vIns := vIns.OwnerInsert;
        end;
        if (vInsLayer <> nil) and (Result = clByLayer) then
          Result := vInsLayer.Color;
      end;
    end;
  end // speed up
  else
  begin
    if E.Layer <> nil then
      vLayer := E.Layer // evg speed up
    else
      Result := clNone;
  end;
  if (Result = clByLayer) and (vLayer <> nil) then
    Result := vLayer.Color;
  // It should be Layer.name = '0' and Entity.color = ByLayer!
  if (Result = clByBlock) or (Result = clByLayer) then
    Result := clNone;
end;

{$ENDIF}

function EntLayer(E: TsgDXFEntity; Ins: TsgDXFInsert): TsgDXFLayer;
var
  vContainerLayer: TsgDXFLayer;
begin
  Result := E.Layer;
  if (Result <> nil) then
  begin
    vContainerLayer := Result.ContainerLayer;
    if Assigned(vContainerLayer) then
      Result := vContainerLayer;
  end;
  if (Ins <> nil) and ((Result = nil) or (Result.Name = '0')) then
    Result := Ins.RealLayer;
end;

{ All operations with lineweights }
function EntLineWeight(E: TsgDXFEntity; Ins: TsgDXFInsert): Double;
var
  vIns: TsgDXFInsert;
  Entity: TsgDXFEntity;
begin
  if not E.HasLineWeight then
  begin
    Result := 0;
    Exit;
  end;
  Result := E.LineWeight;
  if Result >= 0 then
    Exit;
  if Result < fLineWeightByBlock { fLineWeightDefault - for future versions }
  then
    Result := 0;
  if E.Layer = nil then
    Exit;
  Entity := E;
  vIns := Ins;
  if (Result < 0) and (Result <> fLineWeightByBlock) and
    (Result <> fLineWeightDefault) then
    Result := fLineWeightByLayer;
  if (Result = fLineWeightByLayer) and (Entity.Layer.Name <> '0') then
    Result := Entity.Layer.LineWeight;
  if (Result = fLineWeightByLayer) or (Result = fLineWeightByBlock) then
  begin
    if (vIns = nil) or ((Result = fLineWeightByLayer) and
      (Entity.Layer.Name <> '0')) then
    begin
      if Result = fLineWeightByLayer then
        Result := Entity.Layer.LineWeight;
    end
    else
    begin
      while vIns <> nil do
      begin
        if Result = fLineWeightByBlock then
          Result := vIns.LineWeight;
        if (Result = fLineWeightByLayer) and (vIns.Layer <> nil) and
          (vIns.Layer.Name <> '0') then
          Result := vIns.Layer.LineWeight;
        if not((Result = fLineWeightByBlock) or (Result = fLineWeightByLayer))
        then
          Break;
        vIns := vIns.OwnerInsert;
      end;
    end;
  end;
  if (Result = fLineWeightByLayer) then
    Result := Entity.Layer.LineWeight;
  // I should be Layer.name = '0' and Entity.color = ByLayer!
  if (Result = fLineWeightByLayer) or (Result = fLineWeightByBlock) or
    (Result = fLineWeightDefault) then
    Result := 0;
end;

function EntStyle(E: TsgDXFEntity): TPenStyle;
var
  A, B: Single;
  L: TsgLines;
begin
  Result := psSolid;
  if E is TsgCADHatch then
    Exit;
  if not(E is TsgDXFPenLine) then
    Exit;
  L := TsgDXFPenLine(E).Lines;
  if L = nil then
    Exit;
  if L.IsSolid then
    Exit;
  A := L.Elements[0]^.Dash;
  B := L.Elements[1]^.Dash;
  if (A <> 0) and (Abs(B / A) <= 0.25) then
    Result := psDash
  else
    Result := psDot;
  if (Result = psDash) and (L.ElementsCount > 2) and
    (Abs(L.Elements[2]^.Dash / A) <= 0.125) then
    Result := psDashDot;
end;

function EntXrefBlock(E: TsgDXFEntity; Converter: TsgDXFConverter)
  : TsgDXFBlockRecord;
var
  vName, vBlockName: string;
  I, vPos: Integer;
  vGroup: TsgDXFGroup;
begin
  Result := nil;
  if (Converter = nil) or (E = nil) then
    Exit;
  if E is TsgDXFPenTableItem then
    vName := TsgDXFPenTableItem(E).Name;
  if IsXRefInName(vName) then
  begin
    vPos := Pos(cnstXRefNameDelimiter, vName);
    vBlockName := Copy(vName, 1, vPos - 1);
    vGroup := Converter.Sections[csBlockRecords];
    if vBlockName = '' then
      Exit;
    for I := 0 to vGroup.Count - 1 do
      if vGroup.Entities[I] is TsgDXFBlockRecord then
        if SameText(TsgDXFBlockRecord(vGroup.Entities[I]).Name, vBlockName) then
        begin
          Result := TsgDXFBlockRecord(vGroup.Entities[I]);
          Exit;
        end;
  end;
end;

// evg   !!! remove doubling code       {
{
  function EntLineType(E: TsgCADBasePolyline; Ins: TsgDXFInsert): TsgLines;
  var
  vIns: TsgDXFInsert;
  vLayer, vInsLayer: TsgDXFLayer;
  begin
  Result := E.Lines;
  vIns := Ins;
  if Result < 0 then
  Result := clNone;
  vLayer := EntLineType(E, Ins);
  if vLayer = nil then
  Exit;
  if (Result = clByLayer) and (vLayer.Name <> '0') then
  Result := vLayer.Pen.Color;
  if (Result = clByLayer) or (Result = clByBlock) then
  begin
  if (vIns = nil) or
  ((Result = clByLayer) and (vLayer.Name <> '0')) then
  begin
  if Result = clByLayer then
  Result := vLayer.Pen.Color;
  end
  else
  begin
  vInsLayer := nil;
  while vIns <> nil do
  begin
  if Result = clByBlock then
  Result := vIns.Color;
  vInsLayer := EntLayer(vIns, nil);
  if (Result = clByLayer) and (vInsLayer.Name <> '0') then
  Result := vInsLayer.Pen.Color;
  if not ((Result = clByBlock) or (Result = clByLayer)) then
  Break;
  vIns := vIns.Owner;
  end;
  if (vInsLayer <> nil) and (Result = clByLayer) then
  Result := vInsLayer.Pen.Color;
  end;
  end;
  if (Result = clByLayer) then
  Result := vLayer.Pen.Color;
  if (Result = clByBlock) or (Result = clByLayer) then
  Result := clNone;
  end; }

procedure ApplyBulge(const P1, P2: TFPoint; const Bulge: Double;
  const AList: TList; const ANumberOfCircleParts: Integer;
  const AGetPointProc: TsgCreatePPoint; var AResultArc: TsgArcR);
var
  vGenerator: TsgGeneratorShapeEdge;
begin
  vGenerator := TsgGeneratorShapeEdge.Create;
  try
    vGenerator.SetListAndProc(AList, nil, AGetPointProc);
    vGenerator.NumberCirclePart := ANumberOfCircleParts;
    AResultArc := vGenerator.CreateBulgesArc(P1, P2, Bulge);
  finally
    vGenerator.Free;
  end;
end;

function BulgeByArc(AArc: TsgArcR; AVertexPoint: TFPoint;
  const Epsilon: Double = fDoubleResolution): Double;
var
  vArcStart, vArcEnd, vMiddleHord, vMiddleArcPoint, vNextVertexPoint: TFPoint;
  vHeightOfHord, vDistance: Double;
begin
  Result := 0;
  vArcStart := GetPointOnCircle(AArc.Center, AArc.Radius, AArc.AngleS);
  vArcEnd := GetPointOnCircle(AArc.Center, AArc.Radius, AArc.AngleE);
  if not IsEqualFPoints(vArcStart, vArcEnd) then
  begin
    vMiddleHord := MiddleFPoint(vArcStart, vArcEnd);
    vMiddleArcPoint := GetPointOnCircle(AArc.Center, AArc.Radius,
      GetMiddleAngleAP(AArc));
    vHeightOfHord := Sqrt(DistanceFPointSqr(vMiddleHord, vMiddleArcPoint));
    if vHeightOfHord > fExtendedResolution then
    begin
      vDistance := Sqrt(DistanceFPointSqr(vArcStart, vMiddleHord));
      if vDistance > fExtendedResolution then
      begin
        Result := vHeightOfHord / vDistance;
        if IsEqualFPoints(AVertexPoint, vArcStart, Epsilon) then
          vNextVertexPoint := vArcEnd
        else
          vNextVertexPoint := vArcStart;
        if PointClassify(AVertexPoint, vNextVertexPoint, vMiddleArcPoint) = pcLEFT
        then
          Result := -Result;
      end;
    end;
  end;
end;

function GetArcROfVertexes(const AVertex1, AVertex2: TsgDXFVertex;
  var AArc: TsgArcR): Boolean;
begin
  Result := False;
  if AVertex1.Bulge <> 0 then
  begin
    AArc := GetArcROfBulge(AVertex1.Point, AVertex2.Point, AVertex1.Bulge);
    if AArc.Radius > 0 then
      Result := True;
  end;
end;

{ GenerateLineTypes

  Description:
  Lines.Scale = 1 as default;
  '+' - length of the "solid" part of a line;
  '-' - length of the "empty" part of a line;
  '0' - point. }
procedure GenerateLineTypes(AConverter: TsgDXFConverter;
  const AComplex: Boolean);
begin
  GenerateLineTypesEx(AConverter, '', AComplex, False);
end;

procedure GenerateLineTypesEx(const AConverter: TsgDXFConverter;
  const APrefix: string; const AComplex, AIsUniform: Boolean);
const
  cnstCenter = 'CENTER';
  cnstLTypeDash = 'ISO dash';
  cnstLTypeDot = 'ISO dot';
  cnstLTypeDashDot = 'ISO dash dot';
  cnstLTypeDash2Dot = 'ISO dash double-dot';
  cnstLTypeDash3Dot = 'ISO dash triple-dot';
  cnstOTKOS = 'OTKOS'; // |_|_|_|_|_|_|
  cnstDEREV = 'DEREV'; // |___|___|___|
  cnstSETKA = 'SETKA'; // v---^---v---^---
  cnstKOLPROV = 'KOLPROV'; // ---- + ---- + ---- +
  cnstMET = 'MET'; // ----0----0----0
  cnstKAMEN = 'KAMEN'; // ----[]----[]----[]
  cnstBETON = 'BETON'; // |___|___|___|
  cnstSHTRIX = 'SHTRIX'; // __    __    __    __
  cnstKAMSET = 'KAMSET'; // --^--[]--^--[]--^--[]
  cnstKAMDER = 'KAMDER'; // ,--[]--,--[]--,--[]
  cnstMETSET = 'METSET'; // --^--O--^--O--^--O
  cnstTFcable = 'TFcable'; // --0-- --0-- --0--
  cnstELcable = 'ELcable'; // <--->---<--->---
  cnstVELcable = 'VELcable'; // <<--->>---<<--->>---
  cnstVELcable10 = 'VELcable10'; // <<--->>---<<--->>---
  cnstOBR = 'OBR'; // -v-v-v-v-v-
  cnstGRANZ = 'GRANZ'; // __ . . __ . . __ . . __ . . (ISO dash double-dot)
  cnstSTRELA = 'STRELA'; // ----->----->-----
  cnstSTRELA10 = 'STRELA10'; // ----->----->-----
  cnstLVoltageTL = 'LVoltageTL'; // -<----->-<----->-
  cnstHVoltageTL = 'HVoltageTL'; // -<<----->>-<<----->>-
  cnstLTypeDashLongGaps = 'ISO dash long gaps'; // --   --   --
  cnstFromStartToEnd = 'From start to end'; // ->->-
  cnstFromEndToStart = 'From end to start'; // -<-<-

var
  vLType: TsgDXFLineType;
  vStyle: TsgDXFStyle;
  I: Integer;

  function CreateLineType(const ALTypeName: string): TsgDXFLineType;
  begin
    Result := nil;
    if AConverter.LTypeByName(ALTypeName) = nil then
      Result := TsgDXFLineType(AConverter.NewNamedEntity(nil, TsgDXFLineType,
        ALTypeName));
  end;

  procedure LoadLineType(ALType: TsgDXFLineType);
  begin
    AConverter.Loads(ALType);
    AConverter.Sections[csLTypes].AddEntity(ALType);
  end;

begin
  // CONTINUOUS _______________________
  AConverter.AddLineType(APrefix + sContinuous, AIsUniform, []);
  // CENTER ___ _ ___ _ ___ _ ___ _ ___
  AConverter.AddLineType(APrefix + cnstCenter, AIsUniform,
    [1.25, -0.25, 0.25, -0.25]);
  // ACAD_ISO2W100 __ __ __ __ __ __
  AConverter.AddLineType(APrefix + cnstLTypeDash, AIsUniform, [1.2, -0.3]);
  // ACAD_ISO7W100 . . . . . . . . .
  AConverter.AddLineType(APrefix + cnstLTypeDot, AIsUniform, [0, -0.3]);
  // ACAD_ISO10W100 __.__.__.__.__.
  AConverter.AddLineType(APrefix + cnstLTypeDashDot, AIsUniform,
    [1.2, -0.3, 0, -0.3]);
  // ACAD_ISO12W100 __..__..__..__..
  AConverter.AddLineType(APrefix + cnstLTypeDash2Dot, AIsUniform,
    [1.2, -0.3, 0, -0.3, 0, -0.3]);
  // ACAD_ISO14W100 __...__...__...
  AConverter.AddLineType(APrefix + cnstLTypeDash3Dot, AIsUniform,
    [1.2, -0.3, 0, -0.3, 0, -0.3, 0, -0.3]);
  // ACAD_ISO03W100 --   --   --
  AConverter.AddLineType(APrefix + cnstLTypeDashLongGaps, AIsUniform,
    [1.2, -1.8]);

  if AComplex then
  begin
    // Styles section must be empty here
    vStyle := AConverter.StyleByPrimaryFont(cnstFileNameOfShapes);
    if vStyle = nil then
    begin
      vStyle := TsgDXFStyle.Create;
      vStyle.Name := '';
      vStyle.Flags := 1;
      vStyle.PrimaryFont := cnstFileNameOfShapes;
      AConverter.Loads(vStyle);
      AConverter.Sections[csStyles].AddEntity(vStyle);
    end;

    vLType := CreateLineType(cnstBETON);
    if vLType <> nil then
    begin
      vLType.AddDashElement(120);
      vLType.AddComplexElement(4, -0.01, 0, 5, -18.05, -10, vStyle, 2, '');
      vLType.AddDashElement(-0.1);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstDEREV);
    if vLType <> nil then
    begin
      for I := 1 to 3 do
      begin
        vLType.AddDashElement(15);
        vLType.AddDashElement(-0.01);
      end;
      vLType.AddDashElement(15);
      vLType.AddComplexElement(4, -0.01, 0, 7, -18.05, -14, vStyle, 2, '');
      vLType.AddDashElement(-0.01);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstELcable);
    if vLType <> nil then
    begin
      vLType.AddDashElement(6);
      vLType.AddComplexElement(4, -8, 90, 5, 4.0, -5.0, vStyle, 3, '');
      vLType.AddDashElement(-1);
      vLType.AddComplexElement(4, 25, 270, 5, -4.0, 5.0, vStyle, 3, '');
      vLType.AddDashElement(-8);
      vLType.AddDashElement(25);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstVELcable);
    if vLType <> nil then
    begin
      vLType.AddDashElement(8);
      vLType.AddComplexElement(4, -8, 90, 5, 4.0, -5.0, vStyle, 3, '');
      vLType.AddComplexElement(4, -5, 90, 5, 4.0, -5.0, vStyle, 3, '');
      vLType.AddDashElement(-1);
      vLType.AddComplexElement(4, 25, 270, 5, -4.0, 5.0, vStyle, 3, '');
      vLType.AddComplexElement(4, -5, 270, 5, -4.0, 5.0, vStyle, 3, '');
      vLType.AddDashElement(-8);
      vLType.AddDashElement(25);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstTFcable);
    if vLType <> nil then
    begin
      vLType.AddDashElement(8.1);
      vLType.AddComplexElement(4, -8.05, 0, 2, 16.55, 0, vStyle, 5, '');
      vLType.AddDashElement(-1.04);
      vLType.AddDashElement(25.1);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstKAMEN);
    if vLType <> nil then
    begin
      vLType.AddDashElement(90);
      vLType.AddComplexElement(4, -0.01, 0, 9, 0, 0, vStyle, 4, '');
      vLType.AddDashElement(-18);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstKAMDER);
    if vLType <> nil then
    begin
      vLType.AddDashElement(20);
      vLType.AddComplexElement(4, -0.01, 0, 9, 0, 0, vStyle, 4, '');
      vLType.AddDashElement(-18);
      vLType.AddDashElement(40);
      vLType.AddComplexElement(4, -0.01, 0, 5, -7.05, -10, vStyle, 2, '');
      vLType.AddDashElement(40);
      vLType.AddComplexElement(4, -0.01, 0, 5, -7.05, -10, vStyle, 2, '');
      vLType.AddDashElement(-0.01);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstKAMSET);
    if vLType <> nil then
    begin
      vLType.AddDashElement(40);
      vLType.AddComplexElement(4, -0.01, 0, 9, 0, 0, vStyle, 4, '');
      vLType.AddDashElement(-18);
      vLType.AddDashElement(90);
      vLType.AddComplexElement(4, -1, 0, 4, -55.01, 8, vStyle, 11, '');
      vLType.AddDashElement(-0.01);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstKOLPROV);
    if vLType <> nil then
    begin
      vLType.AddDashElement(60);
      vLType.AddComplexElement(4, -20, 0, 4, 0, -8, vStyle, 10, '');
      vLType.AddDashElement(-20);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstMET);
    if vLType <> nil then
    begin
      vLType.AddDashElement(80);
      vLType.AddComplexElement(4, -0.01, 0, 8, 0, 0, vStyle, 5, '');
      vLType.AddDashElement(-16);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstMETSET);
    if vLType <> nil then
    begin
      vLType.AddDashElement(40);
      vLType.AddComplexElement(4, -0.01, 0, 9, 0, 0, vStyle, 5, '');
      vLType.AddDashElement(-18);
      vLType.AddDashElement(90);
      vLType.AddComplexElement(4, -1, 0, 4, -55.01, 8, vStyle, 11, '');
      vLType.AddDashElement(-0.01);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstOTKOS);
    if vLType <> nil then
    begin
      vLType.AddDashElement(24);
      vLType.AddComplexElement(4, -0.01, 0, 6, -8.005, -36, vStyle, 9, '');
      vLType.AddDashElement(-0.1);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstSETKA);
    if vLType <> nil then
    begin
      for I := 1 to 3 do
      begin
        vLType.AddDashElement(22);
        vLType.AddDashElement(-0.01);
      end;
      vLType.AddDashElement(22);
      vLType.AddComplexElement(4, -0.01, 0, 4, -76.01, 8, vStyle, 11, '');
      vLType.AddDashElement(-0.01);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstOBR);
    if vLType <> nil then
    begin
      vLType.AddDashElement(30);
      vLType.AddComplexElement(4, -0.01, 0, 5, 1, 0, vStyle, 13, '');
      vLType.AddDashElement(-0.1);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstSTRELA);
    if vLType <> nil then
    begin
      vLType.AddDashElement(250);
      vLType.AddComplexElement(4, -1, 0, 5, 1, 0, vStyle, 8, '');
      vLType.AddDashElement(-50);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstSTRELA10);
    if vLType <> nil then
    begin
      vLType.AddDashElement(50);
      vLType.AddComplexElement(4, -1, 0, 5, 1, 0, vStyle, 8, '');
      vLType.AddDashElement(-50);
      vLType.AddDashElement(150);
      vLType.AddDashElement(-0.1);
      vLType.AddDashElement(150);
      vLType.AddDashElement(-0.1);
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstLVoltageTL);
    if vLType <> nil then
    begin
      vLType.AddComplexElement(4, 100, 90, 8.333, -16.667, -8.333,
        vStyle, 13, '');
      vLType.AddComplexElement(4, 1533.333, 270, 8.333, 16.667, 8.333,
        vStyle, 13, '');
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstHVoltageTL);
    if vLType <> nil then
    begin
      vLType.AddComplexElement(4, 100, 90, 8.333, -16.667, -8.333,
        vStyle, 13, '');
      vLType.AddComplexElement(4, 25, 90, 8.333, -16.667, -8.333,
        vStyle, 13, '');
      vLType.AddComplexElement(4, 1483.333, 270, 8.333, 16.667, 8.333,
        vStyle, 13, '');
      vLType.AddComplexElement(4, 25, 270, 8.333, 16.667, 8.333,
        vStyle, 13, '');
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstFromStartToEnd);
    if vLType <> nil then
    begin
      vLType.AddDashElement(25);
      vLType.AddComplexElement(4, 100, 90, 8.333, -16.667, -8.333,
        vStyle, 13, '');
      LoadLineType(vLType);
    end;

    vLType := CreateLineType(cnstFromEndToStart);
    if vLType <> nil then
    begin
      vLType.AddDashElement(25);
      vLType.AddComplexElement(4, 100, 270, 8.333, 16.667, 8.333,
        vStyle, 13, '');
      LoadLineType(vLType);
    end;
  end;
end;

procedure GetSinglePts(APts: array of TFPoint; AList: TList);
var
  I: Integer;
  P: PFPoint;
begin
  for I := 0 to AList.Count - 1 do
    Dispose(AList[I]);
  AList.Clear;
  for I := Low(APts) to High(APts) do
  begin
    New(P);
    P^ := APts[I];
    AList.Add(P);
  end;
end;

function GetTextAlignedRotation(const ATextAlign: Integer;
  const ARotation: Double): Double;
begin
  Result := 0;
  if ATextAlign > 0 then // align and iso
  begin
    if (ARotation > 90) and (ARotation < 180) then
      Result := ARotation + 180
    else if (ARotation >= 180) and (ARotation <= 270) then
      Result := ARotation - 180
    else
      Result := ARotation;
  end;
end;

procedure OffsetFRect(var R: TFRect; DX, DY, DZ: Extended);
begin
  R.Left := R.Left + DX;
  R.Top := R.Top + DY;
  R.Right := R.Right + DX;
  R.Bottom := R.Bottom + DY;
  R.Z1 := R.Z1 + DZ;
  R.Z2 := R.Z2 + DZ;
end;

function OffsetFPoint(const APt, AOffset: TFPoint; const Add: Boolean): TFPoint;
begin
  if Add then
    Result := MakeFPoint(APt.X + AOffset.X, APt.Y + AOffset.Y,
      APt.Z + AOffset.Z)
  else
    Result := MakeFPoint(APt.X - AOffset.X, APt.Y - AOffset.Y,
      APt.Z - AOffset.Z);
end;

{
  procedure DoScale2D(var P: TsgCADIterate);
  procedure Cut(var A, B: TFPoint);
  begin
  A.X := A.X - B.X;
  A.Y := A.Y - B.Y;
  A.Z := A.Z - B.Z;
  end;
  var
  P0, P1, P2: TFPoint;
  begin
  if (P.XScale <> 0) or (P.YScale <> 0) then
  Exit;
  P0 := PtXMat(FloatPoint(0, 0), P.Matrix);
  P1 := PtXMat(FloatPoint(0, 1), P.Matrix);
  P2 := PtXMat(FloatPoint(1, 0), P.Matrix);
  Cut(P1, P0);
  Cut(P2, P0);
  P.XScale := Sqrt(P2.X * P2.X + P2.Y * P2.Y);
  P.YScale := Sqrt(P1.X * P1.X + P1.Y * P1.Y);
  P.Angle := 180 / Pi * ArcTan2(P2.Y, P2.X);
  if P2.X * P1.Y < P2.Y * P1.X then
  P.XScale := -P.XScale;
  end;
}
procedure DoScale2D(var P: TsgCADIterate);
var
  P1, P2: TFPoint;
begin
  if (P.XScale <> 0) or (P.YScale <> 0) then
    Exit;
  P1 := MakeFPoint(P.Matrix.M[1, 0], P.Matrix.M[1, 1], P.Matrix.M[1, 2]);
  P2 := MakeFPoint(P.Matrix.M[0, 0], P.Matrix.M[0, 1], P.Matrix.M[0, 2]);
  P.XScale := Sqrt(P2.X * P2.X + P2.Y * P2.Y + P2.Z * P2.Z);
  P.YScale := Sqrt(P1.X * P1.X + P1.Y * P1.Y + P1.Z * P1.Z);
  if Abs(P.XScale) < 1E-10 then
    P.XScale := 0;
  if P2.X * P1.Y < P2.Y * P1.X then
    P.XScale := -P.XScale;
  P.Angle := Degree(ArcTan2(P2.Y, P2.X));
end;

procedure TextParms(var P: TsgCADIterate);
begin
  DoScale2D(P);
end;

procedure UnionFRect(var Dst: TFRect; const Src: TFRect);
begin
  if IsBadRect(Src) then
    Exit;
  ExpandFRect(Dst, Src.TopLeft);
  ExpandFRect(Dst, Src.BottomRight);
end;

function MirrorPoint(const APoint, ACenter: TFPoint): TFPoint;
begin
  Result.X := ACenter.X - APoint.X + ACenter.X;
  Result.Y := ACenter.Y - APoint.Y + ACenter.Y;
  Result.Z := ACenter.Z - APoint.Z + ACenter.Z;
end;

procedure NormFRect(var R: TFRect);
begin
  if R.Left > R.Right then
    SwapSGFloats(R.Left, R.Right);
  if R.Bottom > R.Top then
    SwapSGFloats(R.Bottom, R.Top);
end;

{ IntersectRects

  In Rects Bottom <= Top.

  Returns:
  -1 - AFirstRect not in ARect;
  0 - AFirstRect intersect (part in) ARect;
  1 - AFirstRect full in ARect. }

function IntersectRects(const AFirstRect, ARect: TFRect;
  AMatrix: TFMatrix): Integer;
var
  R: TFRect;
begin
  Result := -1; // not in rect
  if IsBadRect(AFirstRect) or IsBadRect(ARect) then
    Exit;
  R := AFirstRect;
  R.TopLeft := FPointXMat(R.TopLeft, AMatrix);
  R.BottomRight := FPointXMat(R.BottomRight, AMatrix);
  NormFRect(R);
  Result := sgFunction.IntersectFRect2D(ARect, R);
end;

{ IntersectLineRect

  In Rect Bottom <= Top.

  Returns:
  -1 - line not in ARect;
  1 - line full in ARect. }
function IntersectLineRect(const APt1, APt2: TFPoint; ARect: TFRect;
  AMatrix: TFMatrix; AZCompare: Boolean): Integer;
var
  vPt1, vPt2: TFPoint;
begin
  Result := -1; // not in rect
  if IsBadRect(ARect) then
    Exit;
  vPt1 := FPointXMat(APt1, AMatrix);
  vPt2 := FPointXMat(APt2, AMatrix);
  // full in ARect
  if (vPt1.X >= ARect.Left) and (vPt1.X <= ARect.Right) and
    (vPt1.Y >= ARect.Bottom) and (vPt1.Y <= ARect.Top) and
    (vPt2.X >= ARect.Left) and (vPt2.X <= ARect.Right) and
    (vPt2.Y >= ARect.Bottom) and (vPt2.Y <= ARect.Top) then
    Result := 1; // full 2D in rect
  if AZCompare then
  begin
    if (Result = 1) and (vPt1.Z >= ARect.Z1) and (vPt1.Z <= ARect.Z2) and
      (vPt2.Z >= ARect.Z1) and (vPt2.Z <= ARect.Z2) then
      Result := 1 // full 3D in rect
    else
      Result := -1; // not in 3D rect
  end;
end;

function GetLineInViewPort(var APt1, APt2: TFPoint; ARect: TFRect;
  AMatrix: TFMatrix): Boolean;

  function GetYByX(X: Single): Single;
  begin
    Result := BadSingValue;
    if ((APt1.X > X) and (APt2.X < X)) or ((APt1.X < X) and (APt2.X > X)) then
      Result := APt1.Y + (APt2.Y - APt1.Y) * (X - APt1.X) / (APt2.X - APt1.X);
    if (Result < ARect.Bottom) or (Result > ARect.Top) then
      Result := BadSingValue;
  end;

  function GetXByY(Y: Single): Single;
  begin
    Result := BadSingValue;
    if ((APt1.Y > Y) and (APt2.Y < Y)) or ((APt1.Y < Y) and (APt2.Y > Y)) then
      Result := APt1.X + (APt2.X - APt1.X) * (Y - APt1.Y) / (APt2.Y - APt1.Y);
    if (Result > ARect.Right) or (Result < ARect.Left) then
      Result := BadSingValue;
  end;

var
  vSg: Single;
begin
  Result := False;
  if IsBadRect(ARect) then
    Exit;
  NormFRect(ARect);
  APt1 := FPointXMat(APt1, AMatrix);
  APt2 := FPointXMat(APt2, AMatrix);
  vSg := GetYByX(ARect.Left); // left
  if vSg <> BadSingValue then
  begin
    if APt1.X < ARect.Left then
    begin
      APt1.X := ARect.Left;
      APt1.Y := vSg;
    end
    else
    begin
      APt2.X := ARect.Left;
      APt2.Y := vSg;
    end;
    Result := True;
  end;
  vSg := GetYByX(ARect.Right);
  if vSg <> BadSingValue then
  begin
    if APt2.X > ARect.Right then
    begin
      APt2.X := ARect.Right;
      APt2.Y := vSg;
    end
    else
    begin
      APt1.X := ARect.Right;
      APt1.Y := vSg;
    end;
    Result := True;
  end;
  vSg := GetXByY(ARect.Bottom);
  if vSg <> BadSingValue then
  begin
    if APt1.Y < ARect.Bottom then
    begin
      APt1.Y := ARect.Bottom;
      APt1.X := vSg;
    end
    else
    begin
      APt2.Y := ARect.Bottom;
      APt2.X := vSg;
    end;
    Result := True;
  end;
  vSg := GetXByY(ARect.Top);
  if vSg <> BadSingValue then
  begin
    if APt2.Y > ARect.Top then
    begin
      APt2.Y := ARect.Top;
      APt2.X := vSg;
    end
    else
    begin
      APt1.Y := ARect.Top;
      APt1.X := vSg;
    end;
    Result := True;
  end;
end;

procedure DoExtrusion(var P: TFPoint; const Extr: TFPoint);
begin
  sgFunction.DoExtrusion(P, Extr);
end;

function NotZeroPoint(const P: TFPoint): Boolean;
begin
  Result := (P.X <> 0) or (P.Y <> 0) or (P.Z <> 0);
end;

procedure SetArcParams(const Arc: TsgDXFArc; const AP1, AP2: TFPoint;
  const ABulge: Double);
var
  vArcR: TsgArcR;
begin
  vArcR := GetArcROfBulge(AP1, AP2, ABulge);
  Arc.Point := vArcR.Center;
  Arc.Radius := vArcR.Radius;
  Arc.StartAngle := vArcR.AngleS;
  Arc.EndAngle := vArcR.AngleE;
end;

function SetTextStr(const Value: string): string;
var
  vPos, I: Integer;
begin
  Result := Value;
  if MacroStrings <> nil then
  begin
    for I := 0 to MacroStrings.Count - 1 do
    begin
      vPos := AnsiPos('=', MacroStrings[I]);
      if vPos = 0 then
        Continue;
      ReplaceAnsi(Result, MacroStrings.Names[I], Copy(MacroStrings[I], vPos + 1,
        Length(MacroStrings[I])));
    end;
  end;
  ReplaceAnsi(Result, '%%d', cnstDegree);
  ReplaceAnsi(Result, '%%p', cnstPlusMinusSign);
  ReplaceAnsi(Result, '%%c', cnstDiameterArialUni);
end;

procedure SubStr(var S: AnsiString; var P: PAnsiChar; Limit: PAnsiChar);
var
  P0: PAnsiChar;
  C: TsgNativeInt;
begin
  P0 := P;
  while (P < Limit) and not(P^ in [#10, #13]) do
    Inc(P);
  C := P - P0;
  if P <> Limit then
  begin
    if P^ = #13 then
      Inc(P);
    if P^ = #10 then
      Inc(P);
  end;
  SetLength(S, C);
  if C > 0 then
    Move(P0^, S[1], C);
end;

function BSwap(Value: Integer): Integer;
asm
  {$IFDEF SG_CPUX64}
  MOV EAX,ECX
  {$ENDIF}
  XOR	AL,AL
  BSWAP	EAX
end;

function FileExists(const FileName: string): Boolean;
var
  S: string;
begin
  S := Copy(FileName, 1, 2);
  Result := (S <> '//') and (S <> '\\') and SysUtils.FileExists(FileName);
end;


// function StrPos(Str1, Str2, Limit: PChar): PChar;
// asm
// {$IFDEF SGDEL_XE2}
// {$ELSE}
// PUSH    EDI
// PUSH    ESI
// PUSH    EBX
// OR      EAX,EAX
// JE      @@2
// OR      EDX,EDX
// JE      @@2
// SUB	ECX,EAX
// JBE	@@2
// MOV     EBX,EAX
// MOV     EDI,EDX
// XOR     AL,AL
// PUSH	ECX
// MOV     ECX,0FFFFFFFFH
// REPNE   SCASB
// NOT     ECX
// DEC     ECX
// MOV     ESI,ECX
// POP	ECX
// JE      @@2
// SUB     ECX,ESI
// JBE     @@2
// MOV     EDI,EBX
// LEA     EBX,[ESI-1]
// @@1:    MOV     ESI,EDX
// LODSB
// REPNE   SCASB
// JNE     @@2
// MOV     EAX,ECX
// PUSH    EDI
// MOV     ECX,EBX
// REPE    CMPSB
// POP     EDI
// MOV     ECX,EAX
// JNE     @@1
// LEA     EAX,[EDI-1]
// JMP     @@3
// @@2:    XOR     EAX,EAX
// @@3:    POP     EBX
// POP     ESI
// POP     EDI
// {$ENDIF}
// end;

function StrIndex(const S: string; const Map: array of string): Integer;
begin
  Result := IndexOfStrings(S, Map);
end;

function WideStrScan(const S: WideString; const C: WideChar): Integer;
var
  vLen: Integer;
begin
  Result := 1;
  vLen := Length(S);
  while (Result <= vLen) and (S[Result] <> C) do
    Inc(Result);
  if Result > vLen then
    Result := 0;
end;

procedure CopyEntitiesLnk(const ADest, ASource: TsgDXFEntity);
var
  I: Integer;
begin
  ADest.Clear(True);
  for I := 0 to ASource.Count - 1 do
    ADest.AddEntity(ASource[I]);
end;

procedure CopyEntitiesLnk(const ADest: TList; const ASource: TsgDXFEntity);
var
  I: Integer;
begin
  ADest.Count := ASource.Count;
  for I := 0 to ASource.Count - 1 do
    ADest.List[I] := ASource[I];
end;

procedure CopyEntitiesLnk(const ADest: TsgDXFEntity; const ASource: TList);
var
  I: Integer;
begin
  ADest.Clear(True);
  for I := 0 to ASource.Count - 1 do
    ADest.AddEntity(ASource.List[I]);
end;

function IsCADGradient(const AEntity: TsgDXFEntity): Boolean;
begin
  Result := (AEntity is TsgCADGradientPolygon) and
    (TsgCADGradientPolygon(AEntity).FType <> gtNone);
end;

function IsEntity(const AEntity: TObject): Boolean;
begin
  Result := False;
  try
    if AEntity is TsgDXFEntity then
      Result := True;
  except
  end;
end;

function IsIncludeBlock(const Value1, Value2: Pointer): Boolean;
begin
  Result := (TObject(Value1) is TsgDXFInsert) and
    (TsgDXFInsert(Value1).Block = Value2);
end;

function IsIncludeStyle(const Value1, Value2: Pointer): Boolean;
begin
  Result := False;
  if Value1 <> nil then
    Result := TsgDXFEntity(Value1).HasTextStyle(Value2);
end;

function IsIncludeDimStyle(const Value1, Value2: Pointer): Boolean;
begin
  Result := False;
  if Value1 <> nil then
    Result := TsgDXFEntity(Value1).HasDimesionStyle(Value2);
end;

function IsIncludeAllDimesionStyle(const Value1, Value2: Pointer): Boolean;
begin
  Result := False;
  if Value1 <> nil then
    Result := TsgDXFEntity(Value1).HasDimesionStyle;
end;

function ReLoadEntitiesInBlock(const AConv: TsgDXFConverter;
  const ABlock: TsgDXFBlock; const AChanged: TsgDXFEntity;
  const AProc: TsgProcEqual; const ABox: PFRect): Boolean;
var
  I, J: Integer;
  vEnt: TsgDXFEntity;
  vInsReload: Boolean;

  procedure LoadEnt;
  begin
    Result := True;
    if ABox <> nil then
    begin
      UnionFRect(ABox^, vEnt.Box);
      if (vEnt.EntType = ceDimension) and TsgDXFDimension(vEnt).IsInternalDimension
      then
        TsgDXFDimension(vEnt).GenerateBlock(AConv);
      AConv.Loads(vEnt);
      UnionFRect(ABox^, vEnt.Box);
    end
    else
      AConv.Loads(vEnt);
  end;

begin
  Result := False;
  if ABox <> nil then
    ABox^ := cnstBadRect;
  if ABlock = nil then
    Exit;
  for I := 0 to ABlock.Count - 1 do
  begin
    vEnt := ABlock.Entities[I];
    if AProc(vEnt, AChanged) then
      LoadEnt
    else
    begin
      if vEnt is TsgDXFInsert then
      begin
        vInsReload := False;
        for J := 0 to TsgDXFInsert(vEnt).Attribs.Count - 1 do
        begin
          if AProc(TsgDXFInsert(vEnt).Attribs.List[J], AChanged) then
          begin
            vInsReload := True;
            AConv.Loads(TsgDXFInsert(vEnt).Attribs.List[J]);
          end;
        end;
        if ReLoadEntitiesInBlock(AConv, TsgDXFInsert(vEnt).Block, AChanged,
          AProc, nil) then
          vInsReload := True;
        if vInsReload then
          LoadEnt;
      end;
    end;
  end;
  if Result then
  begin
    ABlock.IsLoaded := False;
    AConv.Loads(ABlock);
    if ABlock.Layout <> nil then
      ABlock.IsLoaded := False;
  end;
end;

function ReLoadEntities(const AImage: Pointer; const AChanged: TsgDXFEntity;
  const AProc: TsgProcEqual): TFRect;
var
  vImg: TsgCADImage absolute AImage;
  I: Integer;
  vBox: TFRect;
begin
  Result := cnstBadRect;
  if (vImg.CurrentLayout <> nil) and ReLoadEntitiesInBlock(vImg.Converter,
    vImg.CurrentLayout.PaperSpaceBlock, AChanged, AProc, @vBox) then
    UnionFRect(Result, vBox);
  for I := 0 to vImg.LayoutsCount - 1 do
  begin
    if vImg.CurrentLayout <> vImg.Layouts[I] then
      ReLoadEntitiesInBlock(vImg.Converter, vImg.Layouts[I].PaperSpaceBlock,
        AChanged, AProc, nil);
  end;
end;

procedure AddVertexList(const AList: TList; const APoint: TFPoint);
begin
  AddVertexInList(AList, APoint);
end;

function AddVertexInList(const AList: TList; const APoint: TFPoint;
  const ABulge: Double = 0): TsgDXFVertex;
begin
  Result := TsgDXFVertex.Create;
  AList.Add(Result);
  Result.Point := APoint;
  if ABulge <> 0 then
    Result.Bulge := ABulge;
end;

function AddVertexInPolyline(const APoly: TsgDXFPolyline; const APoint: TFPoint;
  const ABulge: Double = 0): TsgDXFVertex;
begin
  Result := AddVertexInList(APoly.FEntities, APoint, ABulge);
end;

procedure AddVertesesInPolyline(const APoly: TsgDXFPolyline;
  const APoints: TList);
var
  I: Integer;
begin
  for I := 0 to APoints.Count - 1 do
    AddVertexInPolyline(APoly, PFPoint(APoints.List[I])^);
end;

function CreateCADEllipticArc(const APoint, ARatPt1, ARatPt2: TFPoint;
  const APStart, APEnd: PFPoint): TsgDXFEllipse;
var
  vRatio: Double;
  vMajorPoint: TFPoint;
begin
  Result := nil;
  if SetRatioAndMajorPointByPoints(APoint, ARatPt1, ARatPt2, vRatio, vMajorPoint)
  then
  begin
    Result := TsgDXFEllipse.Create;
    Result.Point := APoint;
    Result.Ratio := vRatio;
    Result.EndPoint := vMajorPoint;
    Result.StartAngle := 0;
    Result.EndAngle := 360;
    if APStart <> nil then
      Result.StartAngle := sgFunction.GetAngleParam(Result.Point, Result.RadPt,
        Result.Ratio, APStart^, False);
    if APEnd <> nil then
      Result.EndAngle := sgFunction.GetAngleParam(Result.Point, Result.RadPt,
        Result.Ratio, APEnd^, False);
  end;
end;

function FindByHandle(const AList: TList; const AHandle: UInt64;
  var AIndex: Integer): Boolean;
{$IFDEF SGDEL_XE2}
begin
  Result := False;
  AIndex := AList.Count - 1;
  while (AIndex >= 0) and not Result do
    if TsgDXFEntity(AList.List[AIndex]).Handle = AHandle then
      Inc(Result)
    else
      Dec(AIndex);
end;
{$ELSE}

var
  vPList: PPointerList;
begin
  Result := False;
  AIndex := AList.Count - 1;
  vPList := @AList.List[0];
  while (AIndex >= 0) and not Result do
    if TsgDXFEntity(vPList^[AIndex]).Handle = AHandle then
      Inc(Result)
    else
      Dec(AIndex);
end;
{$ENDIF}

function FindByHandle(const AOwner: TsgDXFEntity; const AHandle: UInt64;
  var AIndex: Integer): Boolean;
begin
  AIndex := AOwner.IndexOfHandle(AHandle);
  Result := AIndex > -1;
end;

function FindChildByEntName(const AOwner: TsgDXFEntity; const AName: string;
  const ACaseSensitive: Boolean; var AIndex: Integer): Boolean;
type
  TCompareFunc = function(const S1, S2: string): Integer;
var
  CompareFunc: TCompareFunc;
begin
  Result := False;
  AIndex := AOwner.Count - 1;
  if ACaseSensitive then
    CompareFunc := AnsiCompareStr
  else
    CompareFunc := AnsiCompareText;
  while (AIndex >= 0) and not Result do
    if CompareFunc(AName, AOwner[AIndex].EntName) = 0 then
      Inc(Result)
    else
      Dec(AIndex);
end;

procedure DimStylePropsToHeadVarStruct(const ADimStyle: TsgDXFDimensionStyle;
  const AConv: TsgDXFConverter);
var
  vHeader: TsgHeadVarStruct;
begin
  vHeader := AConv.HeadVarStruct;
  // vHeader.DimProps.Alt := //Boolean;
  // vHeader.DimProps.AltF := //Double;
  // vHeader.DimProps.APost := //string;
  vHeader.DimProps.Asz := ADimStyle.ArrowSize; // Double;
  vHeader.DimProps.Sah := ADimStyle.DIMSAH;
  vHeader.DimProps.Arrows.Blk := ADimStyle.DIMBLKT; // Byte;
  vHeader.DimProps.Arrows.Blk1 := ADimStyle.DIMBLK1T; // Byte;
  vHeader.DimProps.Arrows.Blk2 := ADimStyle.DIMBLK2T; // Byte;
  vHeader.DimProps.Arrows.LrBlk := ADimStyle.DIMLDRBLKT; // Byte;
  vHeader.DimProps.Cen := ADimStyle.SizeCenterMark; // Double;
  vHeader.DimProps.ClrD := ADimStyle.DIMCLRD; // TsgColorCAD;
  vHeader.DimProps.ClrE := ADimStyle.DIMCLRE; // TsgColorCAD;
  vHeader.DimProps.ClrT := ADimStyle.DIMCLRT; // TsgColorCAD;
  vHeader.DimProps.SD1 := ADimStyle.DIMSD1; // Boolean;
  vHeader.DimProps.SD2 := ADimStyle.DIMSD2; // Boolean;
  vHeader.DimProps.SE1 := ADimStyle.DIMSE1; // Boolean;
  vHeader.DimProps.SE2 := ADimStyle.DIMSE2; // Boolean;
  vHeader.DimProps.Dec := ADimStyle.DIMDEC; // Integer;
  vHeader.DimProps.Exe := ADimStyle.ExtLineExt; // Double;
  vHeader.DimProps.Exo := ADimStyle.ExtLineOffset; // Double;
  vHeader.DimProps.GAP := ADimStyle.TextOffset; // Double;
  vHeader.DimProps.LFac := ADimStyle.GetLFAC; // Double;
  vHeader.DimProps.LwD := ADimStyle.DIMLWD; // Double;
  vHeader.DimProps.LwE := ADimStyle.DIMLWE; // Double;
  // vHeader.DimProps.Post := //string;
  vHeader.DimProps.Scale := ADimStyle.Scale; // Double;
  vHeader.DimProps.Tad := Integer(ADimStyle.TextPosVert); // Integer;
  vHeader.DimProps.Tih := ADimStyle.DIMTIH; // Boolean;
  vHeader.DimProps.Tix := ADimStyle.DIMTIX; // Integer;
  vHeader.DimProps.Toh := ADimStyle.DIMTOH; // Boolean;
  vHeader.DimProps.Txt := ADimStyle.TextHeight; // Double;
  AConv.HeadVarStruct := vHeader;
end;

function CheckStandartNames(var AName: string): Boolean;
const
  cnstLineTypesDefault: array [0 .. 2] of string = (sByLayer, sContinuous,
    sByBlock);
var
  I: Integer;
  vNameUpper: string;
begin
  Result := False;
  if Length(AName) > 0 then
  begin
    vNameUpper := AnsiUpperCase(AName);
    for I := Low(cnstLineTypesDefault) to High(cnstLineTypesDefault) do
    begin
      if vNameUpper = AnsiUpperCase(cnstLineTypesDefault[I]) then
      begin
        AName := cnstLineTypesDefault[I];
        Result := True;
        Break;
      end;
    end;
  end;
end;

function SetBlockByInsert(const Entity: TsgDXFEntity;
  const Converter: TsgDXFConverter): Boolean;
var
  vInsert: TsgDXFInsert;
begin
  Result := False;
  if Entity is TsgDXFInsert then
  begin
    vInsert := TsgDXFInsert(Entity);
    if Assigned(vInsert.Block) and (vInsert.Block.ClassType = TsgLinkObject)
    then
      vInsert.Resolve(Converter);
    if (vInsert.Block = nil) and (Entity is TsgDXFDimension) then
      TsgDXFDimension(Entity).GenerateBlock(Converter);
    Result := Assigned(vInsert.Block);
  end;
end;

procedure ResetHandleEntity(const AEntity: TsgDXFEntity;
  const AConv: TsgDXFConverter);
var
  I: Integer;
begin
  if Assigned(AEntity) then
  begin
    AEntity.Handle := cnstBadHandle;
    // AConv.SetHandle(AEntity);
    for I := 0 to AEntity.Count - 1 do
      ResetHandleEntity(AEntity.Entities[I], AConv);
  end;
end;
{$IFDEF DEMO}

function DrawSGBlock(AOwner: TsgDXFEntity; const AConv: TsgDXFConverter)
  : TsgDXFEntity;
const
  cnstTrialMessagesCount: Integer = 3;
const
  cnstXDATAITEMS = 'XDATAITEMS';
  cnstXDATA = 'XDATA';
  cnstMessage = 'CAD Import VCL demo - please register at www.cadsofttools.com';
  cnstRectWidth = 1 / 2;
  cnstLineSpacingFactor = 1;
  cnstTextHeight = 1 / 30;
var
  I, J, C, K, vIndex: Integer;
  vMText: TsgDXFMText;
  vSGBlock: TsgDXFBlock;
  vXData, vXDataItems: TsgDXFDictionary;
  vInsert: TsgDXFInsert;
  vNeedLoaded, vNeedRecreate: Boolean;
  vBox: TFRect;
  vDelta: TFPoint;
  vLayer: TsgDXFLayer;

  procedure InitMessage(const AMText: TsgDXFMText);
  begin
    AMText.RectWidth := cnstRectWidth;
    AMText.LineSpacingFactor := cnstLineSpacingFactor;
    AMText.Height := cnstTextHeight;
    AMText.ColorCAD := MakeColorCAD(acIndexColor, clDXFBlackWhite);
    AMText.Text := cnstMessage;
    AMText.Visible := True;
    AMText.Visibility := True;
    AMText.Point := cnstFPointZero;
  end;

begin
  vLayer := TsgDXFLayer(AConv.Sections[csLayers].FindEntByName
    (AConv.HeadVarStruct.CLayer));
  if not Assigned(vLayer) or ((not vLayer.Visible) or vLayer.Frozen) then
  begin
    I := 0;
    vLayer := nil;
    while (I < AConv.Sections[csLayers].Count) and not Assigned(vLayer) do
    begin
      vLayer := TsgDXFLayer(AConv.Sections[csLayers][I]);
      if (not vLayer.Visible) or vLayer.Frozen then
        vLayer := nil;
      Inc(I);
    end;
  end;
  vXData := TsgDXFDictionary(AConv.Sections[csObjects].FindEntByName
    (cnstXDATA));
  if not Assigned(vXData) then
  begin
    vXData := TsgDXFDictionary.Create;
    vXData.Name := cnstXDATA;
    vXData.Loaded(AConv);
    AConv.Sections[csObjects].AddEntity(vXData);
  end;
  vIndex := AConv.Sections[csObjects].IndexOfEntity(vXData);
  vSGBlock := TsgDXFBlock(vXData.FindEntByName(cnstCompany));
  if not Assigned(vSGBlock) then
  begin
    vSGBlock := TsgDXFBlock.Create;
    vSGBlock.Name := cnstCompany;
    vXData.AddEntity(vSGBlock);
  end;
  vSGBlock.Layer := vLayer;
  vMText := nil;
  if (vSGBlock.Count > 0) and (vSGBlock[0] is TsgDXFMText) then
    vMText := TsgDXFMText(vSGBlock[0]);
  if not Assigned(vMText) then
  begin
    vMText := TsgDXFMText.Create;
    vSGBlock.AddEntity(vMText);
    vNeedLoaded := True;
  end
  else
  begin
    vNeedLoaded := (vMText.Text <> cnstMessage) or not IsEqual(vMText.RectWidth,
      cnstRectWidth) or not IsEqual(vMText.LineSpacingFactor,
      cnstLineSpacingFactor) or not IsEqual(vMText.Height, cnstTextHeight) or
      not IsEqualColorCAD(vMText.ColorCAD, MakeColorCAD(acIndexColor,
      clDXFBlackWhite)) or not vMText.Visible or
      not IsEqualFPoints(vMText.Point, cnstFPointZero);
  end;
  if vNeedLoaded then
  begin
    InitMessage(vMText);
    vMText.Loaded(AConv);
    vSGBlock.IsLoaded := False;
    vSGBlock.Loaded(AConv);
    AConv.Sections[csBlockRecords].RemoveEntity(vSGBlock.BlockRecord);
  end;
  if Assigned(vMText.Block) then
    for I := 0 to vMText.Block.Count - 1 do
      vMText.Block[I].Visibility := True;
  vMText.Layer := vLayer;
  vSGBlock.Offset := cnstFPointZero;
  vSGBlock.Visible := True;
  vSGBlock.Visibility := True;
  vXDataItems := TsgDXFDictionary(AConv.Sections[csObjects].FindEntByName
    (cnstXDATAITEMS));
  if not Assigned(vXDataItems) then
  begin
    vXDataItems := TsgDXFDictionary.Create;
    vXDataItems.Name := cnstXDATAITEMS;
    vXDataItems.Loaded(AConv);
    AConv.Sections[csObjects].InsertEntity(vIndex, vXDataItems);
  end;
  vNeedRecreate := False;
  C := cnstTrialMessagesCount;
  I := 0;
  while (I < C) and not vNeedRecreate do
  begin
    J := 0;
    while (J < C) and not vNeedRecreate do
    begin
      K := I * C + J;
      if (K < vXDataItems.Count) and (vXDataItems[K] is TsgDXFInsert) and
        (TsgDXFInsert(vXDataItems[K]).Block = vSGBlock) then
        Inc(J)
      else
        Inc(vNeedRecreate);
    end;
    Inc(I);
  end;
  if vNeedRecreate then
  begin
    vXDataItems.Clear(True);
    for I := 0 to C - 1 do
      for J := 0 to C - 1 do
      begin
        vInsert := TsgDXFInsert.Create;
        vInsert.Block := vSGBlock;
        vXDataItems.AddEntity(vInsert);
      end;
  end;
  vBox := AOwner.Box;
  vDelta.X := (vBox.Right - vBox.Left) / C;
  vDelta.Y := (vBox.Top - vBox.Bottom) / C;
  vDelta.Z := (vBox.Z2 - vBox.Z1) / C;
  for I := 0 to C - 1 do
    for J := 0 to C - 1 do
    begin
      K := I * C + J;
      vInsert := TsgDXFInsert(vXDataItems[K]);
      vInsert.Scale := MakeFPoint(vDelta.X, vDelta.Y, 1);
      vInsert.Point := MakeFPoint(vBox.Left + I * vDelta.X,
        vBox.Top - J * vDelta.Y, (vBox.Z2 - vBox.Z1) / 2);
      vInsert.Layer := vLayer;
      vInsert.Visible := True;
      vInsert.Visibility := True;
      vInsert.Loaded(AConv);
    end;
  Result := vXDataItems;
end;
{$ENDIF}

function TryLinkToName(const AEnt: TsgDXFEntity): string;
begin
  Result := '';
  if Assigned(AEnt) then
    if AEnt.ClassType = TsgLinkObject then
      Result := TsgLinkObject(AEnt).Name
    else
      Result := AEnt.Name;
end;

{ TsgMTextParser }

constructor TsgMTextParser.Create(const AConv: TsgDXFConverter);
begin
  inherited Create;
  FListCarry := TList.Create;
  FLevels := TsgIntegerList.Create;
  FConverter := AConv;
  FNeedSetupOptions := False;
end;

destructor TsgMTextParser.Destroy;
begin
  FreeList(FListCarry);
  FLevels.Free;
  inherited Destroy;
end;

function TsgMTextParser.Parse(const Source, Dest: TsgDXFEntity): Boolean;
var
  vText: TsgDXFText;
  I: Integer;
  vIsDestBlock, vHasDivision: Boolean;
  vDestWidth: Double;
begin
  Result := False;
  FHasLine := False;
  vHasDivision := False;
  FDest := Dest;
  FSource := TsgDXFMText(Source);
  vIsDestBlock := Dest is TsgDXFBlock;
  if vIsDestBlock then
  begin
    FDest.Clear;
    TsgDXFBlock(FDest).IsLoaded := False;
  end;
  FDestWidth := FSource.RectWidth;
  FString := SetTextStr(FSource.Text);
  if Length(Trim(FString)) = 0 then
    Exit;
  FLevels.Count := 0;
  ClearList(FListCarry);
  FIndex := 1;
  FLength := Length(FString);
  FLenByRow := 0;
  FPos.X := 0;
  FTextParse := cnstTextParseZero;
  vText := CreateDefaultText;
  try
    vText.Text := '0';
    vText.Loaded(FConverter);
    FFontParams := vText.FTextParse^.FontParams;
  finally
    vText.Free;
  end;
  while FIndex <= FLength do
  begin
    ReadParams(vText);
    if (not vText.WinFont) and (fmItalic in vText.Font.Style) then
      vText.ObliqueAngle := 15;
    CarryString(vText);
    FTextParse := vText.FTextParse^;
    FTextParse.TwiddleCount := 0;
    if not IsTextEmpty(vText) then
    begin
      FTextParse.ParagraphParams.T := 0;
      vText.FTextParse^.HasLine := FHasLine and (FCells <> nil);
      vText.FTextParse^.IsEmpty := vText.GetIsEmpty;
      FHasLine := False;
      FConverter.DoCreate(vText);
      FDest.AddEntity(vText);
      vText.Loaded(FConverter);
      if vText.FTextParse^.TextPos = csNone then
      begin
        if FSource.RectWidth > 0 then
        begin
          if FSource.Hyphenation then // change in future version
            DivisionStringWithHyphenation
          else
            DivisionString;
        end;
        TsgDXFText(FDest.Entities[FDest.Count - 1]).Loaded(FConverter);
        FPos.X := FDest.Entities[FDest.Count - 1].Box.Right;
      end
      else
      begin
        if MakeFraction(vText) = 3 then
          vHasDivision := True;
      end;
    end
    else
      vText.Free;
  end;
  LevelingString;
  if (FDest.Count > 0) and (not(FSource.Align in [0, 1, 4, 7])) then
  begin
    vDestWidth := GetDestWidth;
    if FDestWidth < vDestWidth then
      FDestWidth := vDestWidth;
    if FDestWidth > 0 then
    begin
      if FSource.Hyphenation then
        CorrectTextByHyphenation;
      AdjustChildren;
    end;
  end;
  if vHasDivision then
    CorrectTextByDivision;
  if FCells <> nil then
    CorrectTextByTolerance;
  for I := FDest.Count - 1 downto 0 do
  begin
    vText := TsgDXFText(FDest.Entities[I]);
    if (vText.EntType = ceText) and (vText.FTextParse <> nil) then
    begin
      Result := Result or (not vText.FTextParse.IsEmpty);
      Dispose(vText.FTextParse);
      vText.FTextParse := nil;
    end;
  end;
end;

procedure TsgMTextParser.CorrectTextByDivision;
var
  I, Cnt: Integer;
  vText, vText2: TsgDXFText;
  vCenter: TFPoint;

  procedure AddLine(const ABase: TsgDXFText; const Center: TFPoint);
  var
    vLine: TsgDXFLine;
  begin
    vLine := TsgDXFLine.Create;
    FDest.AddEntity(vLine);
    vLine.AssignEntity(ABase);
    vLine.ColorCAD := ABase.ColorCAD;
    vLine.Point := GetPointOnCircle(Center, ABase.Height, 55);
    vLine.Point1 := GetPointOnCircle(Center, ABase.Height, 235);
    FConverter.Loads(vLine);
  end;

begin
  vCenter := cnstFPointZero;
  I := 0;
  Cnt := FDest.Count;
  while I < Cnt do
  begin
    vText := TsgDXFText(FDest.Entities[I]);
    case vText.FTextParse^.TextPos of
      csDivision:
        begin
          vCenter.X := vText.Box.Right + vText.FTextParse^.FontParams.DX * 0.5;
          vCenter.Y := vText.Box.Bottom;
          AddLine(vText, vCenter);
        end;
      csDivHi:
        begin
          Inc(I);
          if I < Cnt then
          begin
            vText2 := TsgDXFText(FDest.Entities[I]);
            vCenter.X := (vText.Box.Right + vText2.Box.Left) * 0.5;
            vCenter.Y := (vText.Box.Bottom + vText2.Box.Top) * 0.5;
            AddLine(vText, vCenter);
          end
          else
          begin
            vCenter.X := vText.Box.Right +
              vText.FTextParse^.FontParams.DX * 0.5;
            vCenter.Y := vText.Box.Bottom;
            AddLine(vText, vCenter);
          end;
        end;
      csDivend:
        begin
          vCenter.X := vText.Box.Left - vText.FTextParse^.FontParams.DX * 0.5;
          vCenter.Y := vText.Box.Top;
          AddLine(vText, vCenter);
        end;
    end;
    Inc(I);
  end;
end;

procedure TsgMTextParser.CorrectTextByHyphenation;
var
  I, J: Integer;
  vTextFirst, vTextLast: TsgDXFText;
begin
  if not(FDest is TsgDXFBlock) then
    Exit;
  I := 0;
  while I < FDest.Count do
  begin
    if IsFirstText(FDest[I]) then
    begin
      J := I + 1;
      while (J < FDest.Count) and (not IsFirstText(FDest[J])) do
        Inc(J);
      Dec(J);
      while (I <= J) and (Length(Trim(TsgDXFText(FDest[I]).Text)) < 1) do
      begin
        FDest.DeleteEntity(I).Free;
        Dec(J);
      end;
      if I <= J then
      begin
        while (J > I) and (Length(Trim(TsgDXFText(FDest[J]).Text)) < 1) do
        begin
          FDest.DeleteEntity(J).Free;
          Dec(J);
        end;
        vTextFirst := TsgDXFText(FDest[I]);
        vTextLast := TsgDXFText(FDest[J]);
        I := J + 1;
        if vTextFirst <> vTextLast then
        begin
          vTextFirst.Text := TrimLeft(vTextFirst.Text);
          vTextFirst.Loaded(FConverter);
          vTextLast.Text := TrimRight(vTextLast.Text);
        end
        else
          vTextLast.Text := Trim(vTextLast.Text);
        vTextLast.Loaded(FConverter);
      end;
    end
    else
      Inc(I);
  end;
end;

procedure TsgMTextParser.CorrectTextByTolerance;
var
  vIsR14: Boolean;
  LS, LE, vDestCount, I, vIndexLine: Integer;
  vBreak, vIsNotInit: Boolean;
  vT, vTPrev: TsgDXFText;
  vXS, vXE, vYS, vYE, vYM, vMaxHeight, vHeight: Double;

  procedure AddBoundary(const X1, Y1, X2, Y2: Double);
  var
    vPoly: TsgDXFPolyline;
    V: TsgDXFVertex;
  begin
    vPoly := TsgDXFPolyline.Create;
    vPoly.Polyline3D := True;
    FCells.Add(vPoly);
    vPoly.ColorCAD := FCellColor;
    V := TsgDXFVertex.Create;
    vPoly.AddEntity(V);
    V.Point := MakeFPoint(X1, Y1, 0);
    V := TsgDXFVertex.Create;
    vPoly.AddEntity(V);
    V.Point := MakeFPoint(X2, Y1, 0);
    V := TsgDXFVertex.Create;
    vPoly.AddEntity(V);
    V.Point := MakeFPoint(X2, Y2, 0);
    V := TsgDXFVertex.Create;
    vPoly.AddEntity(V);
    V.Point := MakeFPoint(X1, Y2, 0);
    vPoly.Closed := True;
    vPoly.Loaded(FConverter);
  end;

  procedure AddLine(const X1, Y1, X2, Y2: Double);
  var
    vLine: TsgDXFLine;
  begin
    vLine := TsgDXFLine.Create;
    FCells.Add(vLine);
    vLine.ColorCAD := FCellColor;
    vLine.Point := MakeFPoint(X1, Y1, 0);
    vLine.Point1 := MakeFPoint(X2, Y2, 0);
    vLine.Loaded(FConverter);
  end;

begin
  vIsR14 := (FConverter <> nil) and (FConverter.HeadVarStruct.Version = 5);
  vIsNotInit := True;
  vYE := -FSource.Height;
  LE := 0;
  vIndexLine := 0;
  vDestCount := FDest.Count;
  while LE < vDestCount do
  begin
    vMaxHeight := -1;
    vBreak := True;
    LS := LE;
    while LE < vDestCount do
    begin
      vT := TsgDXFText(FDest.Entities[LE]);
      vHeight := vT.FBox.Top - vT.FBox.Bottom;
      if vT.FTextParse^.ParagraphParams.IsFirstText then
        vBreak := not vBreak;
      if vBreak then
        Break;
      if vMaxHeight < vHeight then
        vMaxHeight := vHeight;
      Inc(LE);
    end;
    if vIsR14 then
    begin
      vYS := vYE;
      if vIsNotInit then
      begin
        vYS := vYS + FCellSize + vMaxHeight * 0.5;
        vIsNotInit := False;
      end;
      vYM := vYS - FCellSize - vMaxHeight * 0.5;
      vYE := vYS - FCellSize * 2 - vMaxHeight;
    end
    else
    begin
      vYS := -FCellSize * vIndexLine;
      vYE := vYS - FCellSize;
      vYM := vYS - FCellSize * 0.25;
    end;
    I := LS;
    while I < LE do
    begin
      vT := TsgDXFText(FDest.Entities[I]);
      if vT.FTextParse^.HasLine and (I > LS) then
      begin
        vTPrev := TsgDXFText(FDest.Entities[I - 1]);
        vXS := (vTPrev.FBox.Right + vT.FBox.Left) * 0.5;
        AddLine(vXS, vYS, vXS, vYE);
      end;
      Inc(I);
      if vIsR14 then
        vT.FPoint1.Y := vT.FPoint1.Y + vYM -
          (vT.FBox.Top + vT.FBox.Bottom) * 0.5
      else
        vT.FPoint1.Y := vYM;
      vT.Loaded(FConverter);
    end;
    if vIsR14 then
      vXE := TsgDXFText(FDest.Entities[LE - 1]).FBox.Right + FCellSize
    else
      vXE := TsgDXFText(FDest.Entities[LE - 1]).FBox.Right + FCellSize * 0.25;
    AddBoundary(0, vYS, vXE, vYE);
    Inc(vIndexLine);
  end;
end;

procedure TsgMTextParser.AdjustChildren;
var
  vLengthString: TsgFloat;
  I, K: Integer;
  T: TsgDXFText;
  X: Single;

  procedure Row(AStart, AEnd: Integer);
  var
    L: Integer;

    procedure CalculateLengthString;
    var
      J: Integer;
    begin
      J := AStart;
      while (J < FDest.Count - 1) and
        (not TsgDXFText(FDest.Entities[J + 1])
        .FTextParse^.ParagraphParams.IsFirstText) do
        Inc(J);
      if J < FDest.Count then
        vLengthString := TsgDXFText(FDest.Entities[J]).FBox.Right
      else
        vLengthString := TsgDXFText(FDest.Entities[AStart]).FBox.Right;
    end;

  begin
    if not(FSource.Align in [1, 4, 7]) then
    begin
      if TsgDXFText(FDest.Entities[AStart]).FTextParse^.ParagraphParams.IsFirstText
      then
      begin
        CalculateLengthString;
        X := (FDestWidth - vLengthString);
        if FSource.Align in [2, 5, 8] then
          X := X / 2;
      end;
    end
    else
      X := 0;
    if X < 0 then
      Exit;
    if AStart < 0 then
      AStart := 0;
    for L := AStart to AEnd - 1 do
    begin
      T := TsgDXFText(FDest.Entities[L]);
      T.FPoint.X := T.FPoint.X + X;
      if T.HasSecond then
        T.FPoint1.X := T.FPoint1.X + X;
      T.FStartPoint.X := T.FStartPoint.X + X;
      OffsetFRect(T.FBox, X, 0, 0);
      T.FMatrix.M[3, 0] := T.FMatrix.M[3, 0] + X;
    end;
  end;

begin
  X := 0;
  K := 0;
  vLengthString := 0;
  for I := 0 to FDest.Count - 1 do
  begin
    T := TsgDXFText(FDest.Entities[I]);
    // if T.FBox.Top <> Y then
    begin
      Row(K, I);
      K := I;
    end;
  end;
  Row(FDest.Count - 1, FDest.Count);
end;

procedure TsgMTextParser.CarryString(const AText: TsgDXFText);
var
  I: Integer;
  vText: TsgDXFText;
begin
  AText.FTextParse^.ParagraphParams.IsFirstLine :=
    ((FListCarry.Count = 0) and (FDest.Count = 0)) or (FListCarry.Count > 0);
  if (FListCarry.Count > 0) and
    ((Length(AText.FText) > 0) or (Length(AText.FUnicodeText) > 0)) then
  begin
    AText.FPoint.X := 0;
    AText.FPoint1.X := 0;
    vText := TsgDXFText(FListCarry.First);
    vText.Text := '@';
    vText.Loaded(FConverter);
    if FDest.Count = 0 then
      AText.FTextParse^.Offset.Y := GetTextHeight(vText) + FFontParams.Below +
        FFontParams.DY
    else
      AText.FTextParse^.Offset.Y := FFontParams.DY;
    vText.Free;
    for I := 1 to FListCarry.Count - 1 do
    begin
      vText := TsgDXFText(FListCarry[I]);
      try
        vText.Text := '@';
        vText.Loaded(FConverter);
        AText.FTextParse^.Offset.Y := AText.FTextParse^.Offset.Y +
          GetTextHeight(vText) + FFontParams.Below + FFontParams.DY;
      finally
        vText.Free;
      end;
    end;
    FListCarry.Count := 0;
  end;
end;

procedure TsgMTextParser.CopyTextOptions(const ATextBase, AText: TsgDXFText);
begin
  AText.SetStyle(ATextBase.Style);
  AText.ChangeByStyle(ATextBase.Style); // after SetStyle in MTEXT
  AText.Scale := ATextBase.Scale;
  AText.Layer := ATextBase.Layer;
  AText.Height := ATextBase.Height;
  AText.FVAlign := ATextBase.FVAlign;
  AText.FHAlign := ATextBase.FHAlign;
  AText.FFont.Style := ATextBase.FFont.Style;
  AText.ColorCAD := ATextBase.ColorCAD;
  AText.Font.Name := ATextBase.Font.Name;
  AText.Properties.FFontName := ATextBase.Properties.FFontName;
  AText.Text := ATextBase.Text;
  AText.FInternalFlags := ATextBase.FInternalFlags;
  AText.FTextParse^ := ATextBase.FTextParse^;
  AText.FTextParse^.TwiddleCount := 0;
  AText.FTextParse^.Offset := cnstF2DPointZero;
  AText.FTextParse^.TextPos := csNone;
  AText.FTextParse^.ParagraphParams.IsFirstLine := False;
  // AText.FTextParse^.FOffsetX := 0;
  AText.FLineWeight := ATextBase.FLineWeight;
  AText.ObliqueAngle := ATextBase.ObliqueAngle;
  if (not AText.WinFont) and (fmItalic in AText.Font.Style) then
    AText.ObliqueAngle := 15;
end;

function TsgMTextParser.CreateDefaultText: TsgDXFText;
begin
  Result := TsgDXFText.Create;
  Result.InsideMText := True;
  Result.SetStyle(FSource.Style);
  Result.ChangeByStyle(FSource.Style); // after SetStyle in MTEXT
  Result.Scale := FSource.Style.WidthFactor;
  Result.Layer := FSource.Layer;
  Result.Height := FSource.Height;
  Result.FVAlign := 3;
  Result.HAlign := 0;
  Result.FPoint := MakeFPoint(FPos.X, 0, 0);
  Result.Point1 := Result.FPoint;
  Result.ColorCAD := FSource.ColorCAD;
  Result.Text := '';
  Result.CreateTextParse;
  Result.FTextParse^ := FTextParse;
  Result.FTextParse^.Offset := cnstF2DPointZero;
  Result.FTextParse^.TextPos := csNone;
  Result.FLineWeight := FSource.FLineWeight;
end;

procedure TsgMTextParser.LevelingString;
var
  vFirstIndex, vLastIndex, vModeLine, vDestCount: Integer;
  vMaxHeigth, vMaxHeigthFraction, vDY, vLineSpaceFactor: Double;
  vSizeByTolerance1, vSizeByTolerance2: Double;
  vText, vTextWithMaxHeigth: TsgDXFText;
  vBreak, vIsExactly: Boolean;
  vVAlign: Byte;
  vSign: Integer;

  function GetFractionHeigth(const F, D: TsgDXFText): Double;
  begin
    Result := F.FBox.Top - D.FBox.Bottom + D.FBox.Top - D.FBox.Bottom +
      F.FTextParse^.FontParams.Below;
  end;

  function GetDivisionHeigth(const D: TsgDXFText): Double;
  begin
    Result := (D.FBox.Top - D.FBox.Bottom) * 2;
  end;

  procedure FindIndexs;
  var
    vHeight, vFractionHeight: Double;
  begin
    vVAlign := 0;
    vBreak := True;
    vFirstIndex := vLastIndex;
    vMaxHeigth := -1;
    vMaxHeigthFraction := -1;
    vTextWithMaxHeigth := nil;
    vModeLine := 0;
    vDY := 0;
    while vLastIndex < vDestCount do
    begin
      vText := TsgDXFText(FDest.Entities[vLastIndex]);
      vText.FTextParse^.ParagraphParams.IsFirstText := False;
      if vText.Point.X = 0 then
        vBreak := not vBreak;
      if vBreak then
        Break;
      if vText.FTextParse^.FontParams.DY > vDY then
        vDY := vText.FTextParse^.FontParams.DY;
      if vVAlign < vText.FVAlign then
        vVAlign := vText.FVAlign;
      vHeight := GetTextHeight(vText);
      case vText.FTextParse^.TextPos of
        csNone:
          begin
            if vMaxHeigth < vHeight then
            begin
              vMaxHeigth := vHeight;
              vTextWithMaxHeigth := vText;
            end;
          end;
        csHiWord:
          begin
            if vModeLine < 2 then
              vModeLine := 2;
            vFractionHeight := GetFractionHeigth(vText, vText);
            if vMaxHeigthFraction < vFractionHeight then
              vMaxHeigthFraction := vFractionHeight;
          end;
        csLowWord, csDenominator:
          begin
            if vModeLine < 3 then
              vModeLine := 3;
            vFractionHeight := GetFractionHeigth(vText, vText);
            if vMaxHeigthFraction < vFractionHeight then
              vMaxHeigthFraction := vFractionHeight;
          end;
        csFraction, csIndexes:
          begin
            if vModeLine < 4 then
              vModeLine := 4;
            Inc(vLastIndex);
            if vText.FTextParse^.TextPos = csFraction then
              vText.Font.Style := vText.Font.Style + [fmUnderline];
            vFractionHeight := GetFractionHeigth(vText,
              TsgDXFText(FDest.Entities[vLastIndex]));
            if vMaxHeigthFraction < vFractionHeight then
              vMaxHeigthFraction := vFractionHeight;
          end;
        csDivHi, csDivLow:
          begin
            if vModeLine < 5 then
              vModeLine := 5;
            vFractionHeight := GetDivisionHeigth(vText);
            if vMaxHeigthFraction < vFractionHeight then
              vMaxHeigthFraction := vFractionHeight;
          end;
        csDivision, csDivend:
          begin
            if vModeLine < 6 then
              vModeLine := 6;
            vFractionHeight := vText.FTextParse^.FontParams.Above;
            if vMaxHeigthFraction < vFractionHeight then
              vMaxHeigthFraction := vFractionHeight;
          end;
      end;
      Inc(vLastIndex);
    end;
    if (vFirstIndex > -1) and (vFirstIndex < vDestCount) then
      TsgDXFText(FDest.Entities[vFirstIndex])
        .FTextParse^.ParagraphParams.IsFirstText := True;
  end;

  procedure Leveling;
  var
    I: Integer;
    vFraction: TsgDXFText;
    vIsHeigthByFraction: Boolean;
    vTextByNextPos: TsgDXFText;
    vHeigthByNextPos, vTestHeigthByNextPos: Double;

    procedure MakePosX;
    var
      vPrevText, vPrev2Text: TsgDXFText;
    begin
      if I > vFirstIndex then
      begin
        vPrevText := TsgDXFText(FDest.Entities[I - 1]);
        if I - 1 > vFirstIndex then
        begin
          case vPrevText.FTextParse.TextPos of
            csDenominator:
              begin
                vPrev2Text := TsgDXFText(FDest.Entities[I - 2]);
                if (vPrev2Text.FTextParse^.TextPos in [csFraction, csIndexes])
                  and (vPrev2Text.FBox.Right > vPrevText.FBox.Right) then
                  vPrevText := vPrev2Text;
              end;
          end;
        end;
        if vText.FTextParse^.HasLine then
          vText.FPoint1.X := vPrevText.FBox.Right + vSizeByTolerance1 -
            vText.FTextParse^.FontParams.Left
        else
          vText.FPoint1.X := vPrevText.FBox.Right +
            vPrevText.FTextParse^.FontParams.DX;
      end
      else
      begin
        vPrevText := nil;
        if FCells <> nil then
          vText.FPoint1.X := vText.FPoint1.X + vSizeByTolerance2;
      end;
      if (vText.FTextParse^.TextPos = csDivend) then
        vText.FPoint1.X := vText.FPoint1.X + vText.FTextParse^.FontParams.DX;
      if (vPrevText <> nil) and (vPrevText.FTextParse^.TextPos = csDivision)
      then
        vText.FPoint1.X := vText.FPoint1.X +
          vPrevText.FTextParse^.FontParams.DX;
      if (vText.FTextParse^.TextPos = csDenominator) and (vPrevText <> nil) and
        (vPrevText.FTextParse^.TextPos in [csFraction, csIndexes]) then
        vText.FPoint1.X := vPrevText.FPoint1.X
      else
      begin
        if FCells = nil then
        begin
          if vText.FTextParse^.ParagraphParams.IsFirstText then
          begin
            vText.FPoint1.X := vText.FTextParse^.ParagraphParams.I *
              Integer(vText.FTextParse^.ParagraphParams.IsFirstLine) +
              vText.FTextParse^.ParagraphParams.L;
            if vText.FTextParse^.ParagraphParams.IsFirstLine and
              (vText.FTextParse^.ParagraphParams.I < 0) and (vText.FPoint1.X < 0)
            then
              vText.FPoint1.X := 0;
          end;
          if vText.FTextParse^.ParagraphParams.T > 0 then
            vText.FPoint1.X := GetTextTab(vText);
        end;
      end;
      if I = vFirstIndex then
        vText.FPoint1.X := vText.FPoint1.X - FTextParse.FontParams.Left;
    end;

    procedure MakePosYByFraction(const AText: TsgDXFText);
    begin
      AText.FVAlign := 3;
      if vIsHeigthByFraction then
        AText.FPoint1.Y := FPos.Y -
          (vMaxHeigthFraction - GetFractionHeigth(vText, vText)) * 0.5
      else
      begin
        AText.FPoint1.Y := FPos.Y;
        case vVAlign of
          3:
            AText.FPoint1.Y := AText.FPoint1.Y -
              (vTextWithMaxHeigth.Height - vMaxHeigthFraction);
          4:
            AText.FPoint1.Y := AText.FPoint1.Y -
              (vTextWithMaxHeigth.Height - vMaxHeigthFraction) * 0.5;
        end;
      end;
    end;

    procedure MakePosYByDivision(const AText: TsgDXFText);
    begin
      AText.FVAlign := 3;
      if vIsHeigthByFraction then
        AText.FPoint1.Y := FPos.Y -
          (vMaxHeigthFraction - GetDivisionHeigth(vText)) * 0.5
      else
      begin
        AText.FPoint1.Y := FPos.Y;
        case vVAlign of
          3:
            AText.FPoint1.Y := AText.FPoint1.Y -
              (vTextWithMaxHeigth.Height - vMaxHeigthFraction);
          4:
            AText.FPoint1.Y := AText.FPoint1.Y -
              (vTextWithMaxHeigth.Height - vMaxHeigthFraction) * 0.5;
        end;
      end;
    end;

  begin
    FTextParse := TsgDXFText(FDest.Entities[vFirstIndex]).FTextParse^;
    FPos.Y := FPos.Y - vSign * FTextParse.Offset.Y;
    vTextByNextPos := vTextWithMaxHeigth;
    vHeigthByNextPos := vMaxHeigth;
    if vModeLine = 0 then
    begin
      if vIsExactly then
        vDY := 0;
      if (vTextWithMaxHeigth = nil) and (vFirstIndex < vLastIndex) then
        Exit;
      for I := vFirstIndex to vLastIndex - 1 do
      begin
        vText := TsgDXFText(FDest.Entities[I]);
        vText.FPoint := cnstFPointZero;
        MakePosX;
        vText.FPoint1.Y := FPos.Y - vSign * vLineSpaceFactor *
          (vTextWithMaxHeigth.Height - vText.Height + vDY);
        vText.Loaded(FConverter);
      end;
    end
    else
    begin
      if vMaxHeigthFraction < fAccuracy then
        if vTextWithMaxHeigth = nil then
          vMaxHeigthFraction := FSource.Height
        else
          vMaxHeigthFraction := vTextWithMaxHeigth.Height;
      vIsHeigthByFraction := (vTextWithMaxHeigth = nil) or
        (vMaxHeigthFraction >= vTextWithMaxHeigth.FTextParse^.FontParams.Above);
      I := vFirstIndex;
      while I < vLastIndex do
      begin
        vText := TsgDXFText(FDest.Entities[I]);
        vText.FPoint := cnstFPointZero;
        MakePosX;
        case vText.FTextParse^.TextPos of
          csHiWord:
            begin
              MakePosYByFraction(vText);
              vTestHeigthByNextPos := vText.FBox.Top - vText.FBox.Bottom;
            end;
          csLowWord, csDenominator:
            begin
              MakePosYByFraction(vText);
              vText.FPoint1.Y := vText.FPoint1.Y - vText.FBox.Top +
                vText.FBox.Bottom - vText.FTextParse^.FontParams.Below;
              vTestHeigthByNextPos := vText.FBox.Top - vText.FBox.Bottom;
            end;
          csFraction, csIndexes:
            begin
              vFraction := vText;
              Inc(I);
              vText := TsgDXFText(FDest.Entities[I]);
              vText.FVAlign := 3;
              MakePosYByFraction(vFraction);
              vText.FPoint := cnstFPointZero;
              MakePosX;
              vText.FPoint1.Y := vFraction.FPoint1.Y - vFraction.FBox.Top +
                vFraction.FBox.Bottom - vFraction.FTextParse^.FontParams.Below;
              vFraction.Loaded(FConverter);
              vTestHeigthByNextPos := vText.FBox.Top - vText.FBox.Bottom;
            end;
          csDivHi, csDivision:
            begin
              MakePosYByDivision(vText);
              vTestHeigthByNextPos := vText.FBox.Top - vText.FBox.Bottom;
            end;
          csDivLow, csDivend:
            begin
              MakePosYByDivision(vText);
              vText.FPoint1.Y := vText.FPoint1.Y -
                (vText.FBox.Top - vText.FBox.Bottom);
              vTestHeigthByNextPos := vText.FBox.Top - vText.FBox.Bottom;
            end;
        else
          vText.FPoint1.Y := FPos.Y -
            (vTextWithMaxHeigth.FTextParse^.FontParams.Above -
            vText.FTextParse^.FontParams.Above +
            vText.FTextParse^.FontParams.DY);
          if vIsHeigthByFraction then
          begin
            case vVAlign of
              3:
                vText.FPoint1.Y := vText.FPoint1.Y +
                  (vTextWithMaxHeigth.Height - vMaxHeigthFraction);
              4:
                vText.FPoint1.Y := vText.FPoint1.Y +
                  (vTextWithMaxHeigth.Height - vMaxHeigthFraction) * 0.5;
            end;
          end;
          vText.FVAlign := 3;
          vTestHeigthByNextPos := GetTextHeight(vText);
        end;
        vText.Loaded(FConverter);
        if (vTextByNextPos = nil) or
          (Abs(vTextByNextPos.FPoint1.Y - vHeigthByNextPos) <
          Abs(vText.FPoint1.Y - vTestHeigthByNextPos)) then
        begin
          vTextByNextPos := vText;
          vHeigthByNextPos := vTestHeigthByNextPos;
        end;
        Inc(I);
      end;
    end;
    FPos.Y := vTextByNextPos.Point1.Y - vLineSpaceFactor * vSign *
      (vHeigthByNextPos + FFontParams.Below);
  end;

begin
  if (FConverter <> nil) and (FConverter.HeadVarStruct.Version = 5) then
  begin
    vSizeByTolerance1 := FCellSize * 2;
    vSizeByTolerance2 := FCellSize;
  end
  else
  begin
    vSizeByTolerance1 := FCellSize * 0.5;
    vSizeByTolerance2 := FCellSize * 0.25;
  end;
  vSign := 1 - Integer(not FConverter.IsCrossoverMatrix) shl 1;
  vFirstIndex := 0;
  vLastIndex := 0;
  vDestCount := FDest.Count;
  FPos.Y := 0;
  vIsExactly := FSource.LineSpacingStyle = 2;
  vLineSpaceFactor := FSource.LineSpacingFactor;
  while (vLastIndex < vDestCount) and (vLastIndex <> -1) do
  begin
    FindIndexs;
    Leveling;
  end;
end;

procedure TsgMTextParser.DivisionString;
var
  vP, I, J, vL: Integer;
  vTabValue: Double;
  vText: TsgDXFText;

  procedure ReCalcOffset(AIndex: Integer);
  var
    vText: TsgDXFText;
  begin
    Inc(AIndex);
    if AIndex < FDest.Count then
    begin
      vText := TsgDXFText(FDest.Entities[AIndex]);
      vText.FPoint1.X := 0;
      vText.FPoint.X := 0;
      vText.Loaded(FConverter);
    end;
  end;

  function SplitingText(AIndexSplit: Integer): Boolean;
  var
    vText, vTextBase: TsgDXFText;
    vPosSpace: Integer;
    vStr, vStrCpy, vTextString: string;
    vIsLastSpace: Boolean;

    function AddText: Boolean;
    var
      vLenString: Integer;
    begin
      Result := False;
      vStrCpy := vStr;
      vLenString := Length(vTextString);
      while (vPosSpace < vLenString) and (vTextString[vPosSpace] <> ' ') do
      begin
        Result := True;
        vStr := vStr + vTextString[vPosSpace];
        Inc(vPosSpace);
      end;
      if vPosSpace <= vLenString then
      begin
        Result := True;
        vStr := vStr + vTextString[vPosSpace];
      end;
      Inc(vPosSpace);
    end;

    procedure LoadFirstWord;
    var
      vIsNotSpace: Boolean;
    begin
      vStr := vTextString;
      vPosSpace := 1;
      vIsNotSpace := False;
      while vPosSpace <= Length(vStr) do
      begin
        if vStr[vPosSpace] <> ' ' then
          vIsNotSpace := True
        else if vIsNotSpace then
          Break;
        Inc(vPosSpace);
      end;
      Delete(vStr, vPosSpace, Length(vStr) - vPosSpace + 1);
    end;

  begin
    Result := False;
    vIsLastSpace := True;
    if (TsgDXFText(FDest.Entities[AIndexSplit]).Point.X <> 0) and
      (AIndexSplit - 1 >= 0) and (AIndexSplit - 1 < FDest.Count) then
    begin
      vTextBase := TsgDXFText(FDest.Entities[AIndexSplit - 1]);
      vIsLastSpace := vTextBase.Text[Length(vTextBase.Text)] = ' ';
    end;
    vTextBase := TsgDXFText(FDest.Entities[AIndexSplit]);
    if Length(vTextBase.Text) <= 1 then
      Exit;
    vTextString := vTextBase.Text;
    LoadFirstWord;
    vTextBase.Text := vStr;
    vTextBase.Loaded(FConverter);
    if (Length(vStr) + 1 < Length(vTextString)) then
      vIsLastSpace := vTextString[Length(vStr) + 1] = ' ';

    if vIsLastSpace then
    begin
      if FDestWidth < (FLenByRow + GetBoxWidth(vTextBase)) then
      begin
        vTextBase.FPoint.X := 0;
        vTextBase.FPoint1.X := 0;
        vTextBase.FPoint1.Y := 0;
        FLenByRow := 0;
        vTextBase.Loaded(FConverter);
      end;
    end;
    while FDestWidth > (FLenByRow + GetBoxWidth(vTextBase)) do
    begin
      if not AddText then
        Break;
      vTextBase.Text := vStr;
      vTextBase.Loaded(FConverter);
    end;
    if vStr[Length(vStr)] = ' ' then
    begin
      SetLength(vStr, Length(vStr) - 1);
      vTextBase.Text := vStr;
      vTextBase.Loaded(FConverter);
      if FDestWidth > (FLenByRow + GetBoxWidth(vTextBase)) then
        vStrCpy := vStr;
    end;
    if Length(vStrCpy) = 0 then
      vStrCpy := vStr;
    vTextBase.Text := vStrCpy;
    vTextBase.Loaded(FConverter);
    vPosSpace := Length(vStrCpy);
    vStr := vTextString;
    while vStr[vPosSpace + 1] = ' ' do
      Inc(vPosSpace);
    Delete(vStr, 1, vPosSpace);
    Result := Length(vStr) > 0;
    if Result then
    begin
      vText := TsgDXFText.Create;
      vText.CreateTextParse;
      CopyTextOptions(vTextBase, vText);
      vText.FTextParse^.ParagraphParams.IsFirstText := True;
      vText.Text := vStr;
      vText.FPoint.X := 0;
      vText.FPoint1.X := 0;
      vText.FPoint1.Y := 0;
      FConverter.DoCreate(vText);
      FDest.AddEntity(vText);
      vText.Loaded(FConverter);
    end
    else
      vTextBase.Text := vTextBase.Text + ' ';
  end;

begin
  I := FDest.Count - 1;
  if TsgDXFText(FDest.Entities[I]).Point.X = 0 then
    FLenByRow := 0;
  if TsgDXFText(FDest.Entities[I]).FTextParse^.ParagraphParams.T > 0 then
  begin
    vTabValue := GetTextTab(TsgDXFText(FDest.Entities[I]));
    if FLenByRow < vTabValue then
      FLenByRow := vTabValue;
  end;
  while I < FDest.Count do
  begin
    FLenByRow := FLenByRow + GetTextWidth(FDest.Entities[I]);
    if FLenByRow > FDestWidth then
    begin
      J := I;
      FLenByRow := FLenByRow - GetTextWidth(FDest.Entities[I]);
      vP := AnsiPos(' ', TsgDXFText(FDest.Entities[I]).Text);
      if (vP = 0) and (I > 0) then
      begin
        J := I - 1;
        vText := TsgDXFText(FDest.Entities[J]);
        vP := AnsiPos(' ', vText.Text);
        vL := Length(vText.Text);
        if (vL > 0) and (vText.Text[vL] = ' ') then
          vP := Length(vText.Text);
      end;
      if vP > 0 then
      begin
        if vP = Length(TsgDXFText(FDest.Entities[J]).Text) then
        begin
          ReCalcOffset(J);
          FLenByRow := 0;
        end
        else if not SplitingText(J) then
          FLenByRow := FLenByRow + GetTextWidth(FDest.Entities[I])
        else
          FLenByRow := 0;
      end;
    end;
    Inc(I);
  end;
end;

procedure TsgMTextParser.DivisionStringWithHyphenation;
var
  I, vCopyLength: Integer;
  vTextBase, vTextNew: TsgDXFText;
  vTextWidth: Double;
  vText, vTextPrev: string;
begin
  if not(FDest is TsgDXFBlock) then
  begin
    DivisionString;
    Exit;
  end;
  I := FDest.Count - 1;
  SpliteTextbySpace(FDest, FDest.Count - 1);
  if TsgDXFText(FDest[I]).Point.X = 0 then
    FLenByRow := 0;
  while I < FDest.Count do
  begin
    vTextBase := TsgDXFText(FDest[I]);
    Inc(I);

    vText := vTextBase.Text;
    vCopyLength := Length(vText);
    vTextWidth := GetTextWidth(vTextBase);

    if FLenByRow + vTextWidth > FDestWidth then
    begin
      if I > 1 then
      begin
        vTextPrev := TsgDXFText(FDest[I - 2]).Text;
        if (Length(vTextPrev) > 0) and (vTextPrev[Length(vTextPrev)] = ' ') then
        begin
          vText := TrimLeft(vTextBase.Text);
          vTextBase.Text := vText;
          SetIsFirstTextAndLoad(vTextBase);
          vTextWidth := GetTextWidth(vTextBase);
        end;
      end;

      while FLenByRow + vTextWidth > FDestWidth do
      begin
        Dec(vCopyLength);
        if vCopyLength > 0 then
        begin
          vTextBase.Text := Copy(vText, 1, vCopyLength);
          vTextBase.Loaded(FConverter);
          vTextWidth := GetTextWidth(vTextBase);
        end
        else
          Break;
      end;
    end;

    if vCopyLength > 0 then
    begin
      if vCopyLength < Length(vText) then
      begin
        if vText[vCopyLength + 1] = ' ' then
          vTextBase.Text := vTextBase.Text + ' ';
        Delete(vText, 1, vCopyLength);
        vText := TrimLeft(vText);
        if Length(vText) > 0 then
        begin
          vTextNew := TsgDXFText.Create;
          if I >= FDest.Count then
            FDest.AddEntity(vTextNew)
          else
            FDest.InsertEntity(I, vTextNew);
          vTextNew.CreateTextParse;
          CopyTextOptions(vTextBase, vTextNew);
          vTextNew.Text := vText;
          SetIsFirstTextAndLoad(vTextNew);
          vTextWidth := 0;
        end;
      end;
    end
    else
    begin
      vTextBase.Text := TrimLeft(vText);
      if Length(vTextBase.Text) > 0 then
      begin
        SetIsFirstTextAndLoad(vTextBase);
        vTextWidth := GetTextWidth(vTextBase);
      end
      else
      begin
        Dec(I);
        FDest.RemoveEntity(vTextBase);
        vTextBase.Free;
        vTextWidth := 0;
      end;
    end;

    FLenByRow := FLenByRow + vTextWidth;
  end;
end;

function TsgMTextParser.MakeFraction(const AText: TsgDXFText): Integer;
var
  vPosSlash, vCountSpace, I: Integer;
  vDenominator: TsgDXFText;
  vStrOrg, vStr, vDenom: string;

  procedure Smoothing;
  var
    I: Integer;
  begin
    vCountSpace := Round((Length(vDenominator.Text) - Length(AText.Text))
      / 2 - 0.5);
    vStr := '';
    for I := 0 to vCountSpace do
    begin
      vStr := vStr + ' ';
    end;
    if vCountSpace < 0 then
      vDenominator.Text := vDenominator.Text + vStr
    else
    begin
      if vCountSpace > 0 then
        AText.Text := vStr + AText.Text + vStr;
    end;
  end;

  function CheckSymbol(const C: Char): Boolean;
  begin
    case C of
      ' ', '/', '^', '#':
        Result := True;
    else
      Result := False;
    end;
  end;

begin
  vDenominator := nil;
  Result := 0;
  vPosSlash := AnsiPos('/', AText.Text);
  if vPosSlash = 0 then
  begin
    vPosSlash := AnsiPos('^', AText.Text);
    if vPosSlash > 0 then
      Result := 2
    else
    begin
      vPosSlash := AnsiPos('#', AText.Text);
      if vPosSlash > 0 then
        Result := 3;
    end;
  end
  else
    Result := 1;
  if Result > 0 then
  begin
    vStrOrg := AText.Text;
    if ((Result = 1) and (vPosSlash > 1)) or (Result > 1) then
    begin
      AText.Text := Copy(vStrOrg, 1, vPosSlash - 1);
      if Result = 3 then
        AText.FTextParse^.TextPos := csDivision
      else
        AText.FTextParse^.TextPos := csHiWord;
      AText.Loaded(FConverter);
      Delete(vStrOrg, 1, vPosSlash);
      vPosSlash := 0;
      for I := 1 to Length(vStrOrg) do
      begin
        if vStrOrg[I] <> ' ' then
        begin
          vPosSlash := I;
          Break;
        end;
      end;
    end
    else
    begin
      vPosSlash := 0;
      AText.FTextParse^.TextPos := csLowWord;
      I := 1;
      if I <= Length(AText.Text) then
      begin
        AText.FUnicodeText := '';
        while (I <= Length(AText.Text)) and CheckSymbol(AText.Text[I]) do
          Delete(AText.FText, 1, 1);
      end;
    end;
    if IsTextEmpty(AText) then
    begin
      TsgDXFGroup(FDest).RemoveEntity(AText);
      AText.Free;
      Exit;
    end;
    if vPosSlash > 0 then
    begin
      vDenom := Copy(vStrOrg, vPosSlash, Length(vStrOrg) - vPosSlash + 1);
      if Length(Trim(AText.FText)) > 0 then
      begin
        vDenominator := TsgDXFText.Create;
        vDenominator.CreateTextParse;
        CopyTextOptions(AText, vDenominator);
        vDenominator.Point := AText.Point;
        vDenominator.Point1 := AText.Point1;
        vDenominator.Text := vDenom;
        FConverter.DoCreate(vDenominator);
        FDest.AddEntity(vDenominator);
        case Result of
          2:
            begin
              AText.FTextParse^.TextPos := csIndexes;
              vDenominator.FTextParse^.TextPos := csDenominator;
            end;
          3:
            begin
              AText.FTextParse^.TextPos := csDivHi;
              vDenominator.FTextParse^.TextPos := csDivLow;
              vDenominator.Point := MakeFPoint(AText.Box.Right,
                vDenominator.Point.Y, vDenominator.Point.Z);
              vDenominator.Loaded(FConverter);
            end;
        else
          AText.FTextParse^.TextPos := csFraction;
          vDenominator.FTextParse^.TextPos := csDenominator;
        end;
      end
      else
      begin
        if Result = 3 then
          AText.FTextParse^.TextPos := csDivend
        else
          AText.FTextParse^.TextPos := csDenominator;
        AText.Text := vDenom;
        AText.Loaded(FConverter);
        FPos.X := AText.Box.Right;
      end;
    end;
    case AText.FTextParse^.TextPos of
      csFraction, csIndexes:
        begin
          Smoothing;
          vDenominator.Loaded(FConverter);
          AText.Loaded(FConverter);
          FPos.X := Max(AText.Box.Right, vDenominator.Box.Right);
        end;
      csDivLow, csDivHi, csDivision, csDivend:
        begin
          if vDenominator = nil then
            FPos.X := AText.Box.Right + AText.FTextParse^.FontParams.DX
          else
            FPos.X := Max(AText.Box.Right, vDenominator.Box.Right);
        end;
    end;
  end
  else
  begin
    AText.FTextParse^.TextPos := csNone;
    FPos.X := AText.Box.Right;
  end;
end;

procedure TsgMTextParser.ReadParams(var AText: TsgDXFText);
const
  cnstHeigth = 0.083330266656;

var
  vSetupLastOptions, vDone, vIsChangeLevel, vReadTextOption: Boolean;
  vIndexTextModel: Integer;

  function StringToFloat(AStr: string): TsgFloat;
  var
    vDs: Char;
  begin
    vDs := SetDecimalSeparator('.');
    try
      Result := ConvToFloatDef(AStr, 0.0);
    finally
      SetDecimalSeparator(vDs);
    end;
  end;

  function ReadFloatValue(var Value: Double): Boolean;
  var
    J: Integer;
    S: string;
  begin
    for J := FIndex to FLength do
    begin
      case FString[J] of
        '0' .. '9':
          begin
          end;
        '.', '-':
          begin
          end;
      else
        Break;
      end;
    end;
    Result := J - FIndex > 0;
    if Result then
    begin
      S := Copy(FString, FIndex, J - FIndex);
      Value := StringToFloat(S);
      FIndex := J - 1;
    end
    else
      Value := 0;
  end;

  procedure PAlign;
  begin
    Inc(FIndex);
    case FString[FIndex] of
      '1':
        AText.FVAlign := 4;
      '2':
        AText.FVAlign := 5;
    else
      AText.FVAlign := 3;
    end;
  end;

  procedure PEnter;
  var
    vText: TsgDXFText;
  begin
    if FString[FIndex - 1] <> cnstVertSlash then
    begin
      vText := TsgDXFText.Create;
      FListCarry.Add(vText);
      vText.AssignEntity(AText);
      vText.InsideMText := True;
      vText.CreateTextParse;
      vText.FTextParse^ := vText.FTextParse^;
    end;
  end;

  function IsSplitter(const AIndex: Integer): Boolean;
  begin
    case FString[AIndex] of
      cnstCommaPoint, cnstLeftBracket, cnstRigthBracket, cnstVertSlash:
        Result := True;
      cnstBackSlash:
        begin
          if (AIndex + 2 <= FLength) and (FString[AIndex + 2] = '+') then
            case FString[AIndex + 1] of
              'u', 'm', 'U', 'M':
                Result := False;
            else
              Result := True;
            end
          else
            Result := True;
        end;
    else
      Result := False;
    end;
  end;

  procedure PFont(const AIsSHX: Boolean);
  var
    vFontName, vExt, vSHXFont: string;
  begin
    vSHXFont := '';
    Inc(FIndex);
    while (FIndex <= FLength) and (not IsSplitter(FIndex)) do
    begin
      vFontName := vFontName + FString[FIndex];
      Inc(FIndex);
    end;
    Dec(FIndex);
    if (AnsiPos('\U+', vFontName) > 0) or (AnsiPos('\u+', vFontName) > 0) then
    begin
      if AIsSHX then
      begin
        vSHXFont := sDefaultSHXFont;
        vFontName := ExtractFileName(vSHXFont);
      end
      else
        vFontName := 'Arial';
    end
    else
    begin
      vExt := AnsiUpperCase(ExtractFileExt(vFontName));
      if Length(vExt) = 0 then
      begin
        if AIsSHX then
          vSHXFont := vFontName + '.shx';
      end
      else
      begin
        if vExt = '.SHX' then
        begin
          vSHXFont := vFontName;
          SetLength(vFontName, Length(vFontName) - Length(vExt));
        end;
      end;
    end;
    AText.WinFont := Length(vSHXFont) = 0;
    AText.Font.Name := vFontName;
    AText.Properties.FFontName := vFontName;
    AText.Font.Style := AText.Font.Style - [fmBold, fmItalic];
  end;

  procedure PFontBold;
  begin
    Inc(FIndex);
    if FString[FIndex] = '1' then
      AText.Font.Style := AText.Font.Style + [fmBold]
    else
      AText.Font.Style := AText.Font.Style - [fmBold]
  end;

  procedure PFontColor;
  var
    vStr: string;
    vIsColor: Boolean;
    vIsIndexColor: Boolean;
  begin
    vIsIndexColor := FString[FIndex] = 'C';
    vIsColor := FString[FIndex - 1] <> cnstVertSlash;
    Inc(FIndex);
    while (FIndex <= FLength) and (FString[FIndex] <> cnstCommaPoint) do
    begin
      if FString[FIndex] = cnstVertSlash then
      begin
        Dec(FIndex);
        Break;
      end;
      vStr := vStr + FString[FIndex];
      Inc(FIndex);
    end;
    if vIsColor then
    begin
      if vIsIndexColor then
        AText.ColorCAD := MakeColorCAD(acIndexColor,
          StrToIntDef(vStr, clDXFByBlock))
      else
        AText.ColorCAD := MakeColorCAD(acRGBColor, StrToIntDef(vStr, clBlack));
    end
    else
      AText.Font.Charset := StrToIntDef(vStr, DEFAULT_CHARSET);
  end;

  procedure PFontItalic;
  begin
    Inc(FIndex);
    if FString[FIndex] = '1' then
      AText.Font.Style := AText.Font.Style + [fmItalic]
    else
      AText.Font.Style := AText.Font.Style - [fmItalic];
  end;

  procedure PFraction;
  var
    vFindCommaPoint: Boolean;
  begin
    Inc(FIndex);
    AText.FText := '';
    vFindCommaPoint := FString[FIndex] = cnstCommaPoint;
    while (FIndex <= FLength) and not(vFindCommaPoint) do
    begin
      AText.FText := AText.FText + FString[FIndex];
      Inc(FIndex);
      vFindCommaPoint := FString[FIndex] = cnstCommaPoint;
    end;
    if vFindCommaPoint then
      AText.FTextParse^.TextPos := csFraction
    else
      AText.FText := '\S' + AText.FText;
    if not vIsChangeLevel then
    begin
      vIsChangeLevel := True;
      FLevels.Add(FDest.Count);
    end;
  end;

  procedure PHeight;
  var
    H: string;
    L: Integer;
    V: Double;
    DS: Char;
    vIsKoefHeigth: Boolean;
  begin
    Inc(FIndex);
    L := 0;
    vIsKoefHeigth := False;
    while FIndex < FLength do
    begin
      vIsKoefHeigth := vIsKoefHeigth or (FString[FIndex] = 'x') or
        (FString[FIndex] = 'X');
      if FString[FIndex] = cnstCommaPoint then
        Break
      else if not(CharInSet(FString[FIndex], ['0' .. '9']) or
        (FString[FIndex] = cnstPoint) or (FString[FIndex] = cnstComma)) then
        Break;
      Inc(L);
      Inc(FIndex);
    end;
    H := Copy(FString, FIndex - L, L);
    if H = '' then
      Exit;
    DS := SetDecimalSeparator(cnstPoint);
    try
      V := ConvToFloatDef(H, 1.0);
      if vIsKoefHeigth then
        V := V * AText.Height;
    except
      V := AText.Height;
    end;
    SetDecimalSeparator(DS);
    V := V - AText.Height;
    case AText.VAlign of
      3:
        AText.FPoint.Y := AText.FPoint.Y + V;
      4:
        AText.FPoint.Y := AText.FPoint.Y + V / 2;
    end;
    AText.Height := AText.Height + V;
    if (FIndex < FLength) and (FString[FIndex] = cnstCommaPoint) then
      Dec(FIndex);
  end;

  procedure PLower;
  begin
    if FLevels.Count > 0 then
    begin
      vIndexTextModel := FLevels.Last;
      AText.Height := TsgDXFText(FDest.Entities[vIndexTextModel]).Height;
      AText.Font.Assign(TsgDXFText(FDest.Entities[vIndexTextModel]).Font);
      AText.FPoint.X := TsgDXFText(FDest.Entities[vIndexTextModel]).FPoint.X;
      AText.FPoint.Y := AText.FPoint.Y - AText.Height;
    end;
  end;

  procedure PMCode;
  var
    WCh: WideChar;
  begin
    if FIndex + 1 <= FLength then
      if FString[FIndex + 1] = '+' then
      begin
        Inc(FIndex, 3);
        WCh := AText.GetSymbolFromMultibyte(FConverter,
          StringHexToIntDef(Copy(FString, FIndex, 2), 0),
          StringHexToIntDef(Copy(FString, FIndex + 2, 2), 0),
          StrToIntDef(Copy(FString, FIndex - 1, 1), 0), False);
{$IFDEF VER100}
        AText.FUnicodeText := AText.FUnicodeText + WideString(WCh);
{$ELSE}
        AText.FUnicodeText := AText.FUnicodeText + WCh;
        AText.FText := AText.FUnicodeText;
{$ENDIF}
        vDone := True;
        vIsChangeLevel := True;
        FLevels.Add(FDest.Count);
        Inc(FIndex, 3);
      end
      else
        AText.FText := Copy(FString, FIndex - 1, 2);
  end;

  procedure PReadParagraph; // For future versions
  begin
    while (FIndex <= FLength) and (FString[FIndex] <> cnstCommaPoint) and
      (FString[FIndex] <> cnstVertSlash) do
      Inc(FIndex);
  end;

  procedure PReadForFutureVersions;
  var
    vStr: string;
    J: Integer;
  begin
    for J := FIndex + 1 to FLength do
      if (FString[J] = cnstBackSlash) or (FString[J] = cnstCommaPoint) then
        Break;
    vStr := Copy(FString, FIndex + 1, J - FIndex - 1);
    if Length(vStr) > 0 then
      StringToFloat(vStr);
    FIndex := J;
  end;

  procedure PReadDataOfParapraph;
  var
    vType, vMode, vSize: Integer;
    vDigits: string;
    vIsSetparams: Boolean;
  begin
    vIsSetparams := False;
    vMode := 0;
    vType := -1;
    while vMode = 0 do
    begin
      vDigits := '';
      vMode := -1;
      while FIndex <= FLength do
      begin
        case FString[FIndex] of
          ',':
            begin
              vMode := 0;
              Inc(FIndex);
              Break;
            end;
          ';':
            begin
              vMode := 1;
              Break;
            end;
          'i', 'I':
            vType := 1;
          'l', 'L':
            vType := 2;
          't', 'T':
            vType := 3;
          '-', '.', '0' .. '9':
            vDigits := vDigits + FString[FIndex];
        end;
        Inc(FIndex);
      end;
      case vType of
        1:
          AText.FTextParse^.ParagraphParams.I := 12 * cnstHeigth *
            ConvToFloatDef(vDigits, 0);
        2:
          AText.FTextParse^.ParagraphParams.L := 12 * cnstHeigth *
            ConvToFloatDef(vDigits, 0);
        3:
          begin
            if (AText.FTextParse^.ParagraphParams.TabsCount > 0) and
              (not vIsSetparams) then
            begin
              FillChar(AText.FTextParse^.ParagraphParams.Tabs,
                SizeOf(AText.FTextParse^.ParagraphParams.Tabs), 0);
              AText.FTextParse^.ParagraphParams.TabsCount := 0;
            end;
            vIsSetparams := True;
            vSize := High(AText.FTextParse^.ParagraphParams.Tabs) -
              Low(AText.FTextParse^.ParagraphParams.Tabs);
            if AText.FTextParse^.ParagraphParams.TabsCount < vSize then
            begin
              AText.FTextParse^.ParagraphParams.Tabs
                [AText.FTextParse^.ParagraphParams.TabsCount] := 12 * cnstHeigth
                * ConvToFloatDef(vDigits, 0);
              Inc(AText.FTextParse^.ParagraphParams.TabsCount);
            end;
          end;
      end;
    end;
  end;

  function PUnicode: Boolean;
  var
    Str: string;
    WCh: WideChar;

    procedure AddUni(const AStrUni: string);
    begin
      WCh := WideChar((StringHexToIntDef(Copy(AStrUni, 2, 2), 0) shl 8) or
        StringHexToIntDef(Copy(AStrUni, 4, 2), 0));
{$IFDEF VER100}
      AText.FUnicodeText := AText.FUnicodeText + WideString(WCh);
{$ELSE}
      AText.FUnicodeText := AText.FUnicodeText + WCh;
      AText.FText := AText.FUnicodeText;
{$ENDIF}
    end;

    function GetUni(const AI: Integer): string;
    begin
      Result := '';
      if AI + 7 <= FLength then
      begin
        Result := Copy(FString, AI + 1, 7);
        if FConverter.CheckUnicode then
        begin
          Result := AnsiUpperCase(Result);
          if (Result = cnstDiameterArialUni) or (Result = cnstDiameterUni) then
            Result := '';
        end;
        if (Length(Result) > 0) and (Result[1] = '\') and
          (UpCase(Result[2]) = 'U') then
          Delete(Result, 1, 2)
        else
          Result := '';
      end;
    end;

  begin
    Inc(FIndex);
    Str := Copy(FString, FIndex, 5);
    Inc(FIndex, 4);
    AddUni(Str);
    FNeedSetupOptions := True;
    while FIndex < FLength do
    begin
      Str := GetUni(FIndex);
      if Length(Str) > 0 then
      begin
        Inc(FIndex, 7);
        AddUni(Str);
      end
      else
        Break;
    end;
    Result := True;
    vIsChangeLevel := True;
    FLevels.Add(FDest.Count);
  end;

  procedure PWeigth;
  var
    vStr: string;
    J: Integer;
  begin
    for J := FIndex + 1 to FLength do
      if (FString[J] = cnstBackSlash) or (FString[J] = cnstCommaPoint) then
        Break;
    vStr := Copy(FString, FIndex + 1, J - FIndex - 1);
    if Length(vStr) > 0 then
      AText.Scale := StringToFloat(vStr);
    FIndex := J;
  end;

  procedure PReadTwiddle;
  begin
    Inc(AText.FTextParse^.TwiddleCount);
    AText.FText := AText.FText + ' ';
  end;

  procedure PReadObliqueAngle;
  var
    vRot: Double;
  begin
    Inc(FIndex);
    if ReadFloatValue(vRot) then
    begin
      if not((vRot >= -85) and (vRot <= 85)) then // See AutoCAD MText editor
        vRot := vRot - Round(vRot / 360) * 360;
      AText.ObliqueAngle := vRot;
    end;
  end;

  procedure PReadUnknowData;
  begin
    while (FIndex <= FLength) and (FString[FIndex] <> cnstCommaPoint) and
      (FString[FIndex] <> cnstBackSlash) do
      Inc(FIndex);
  end;

  procedure PMakeTextOption;
  begin
    Inc(FIndex);
    vReadTextOption := True;
    case FString[FIndex] of
      '~':
        PReadTwiddle;
      'A', 'a':
        PAlign;
      'B', 'b':
        PFontBold;
      'C', 'c':
        PFontColor;
      'F', 'f':
        PFont(FString[FIndex] = 'F');
      'H', 'h':
        PHeight;
      'I', 'i':
        PFontItalic;
      'L':
        AText.Font.Style := AText.Font.Style + [fmUnderline];
      'l':
        AText.Font.Style := AText.Font.Style - [fmUnderline];
      'M', 'm':
        PMCode;
      'O':
        AText.Font.Style := AText.Font.Style + [fmStrikeOut];
      'o':
        AText.Font.Style := AText.Font.Style - [fmStrikeOut];
      'P':
        PEnter;
      'p':
        begin
          if FIndex < FLength then
          begin
            if CharInSet(UpCase(FString[FIndex + 1]), ['L', 'I', 'T']) then
              PReadDataOfParapraph
            else
              PReadParagraph;
          end
          else
            vReadTextOption := False;
        end;
      'S', 's':
        PFraction;
      'T', 't':
        PReadForFutureVersions;
      'U', 'u':
        vDone := PUnicode;
      'W', 'w':
        PWeigth;
      '$':
        PLower;
      'Q':
        PReadObliqueAngle;
    else
      begin
        vReadTextOption := False;
        if FIndex > 1 then
          case FString[FIndex - 1] of
            cnstBackSlash:
              begin
                AText.FText := AText.FText + cnstBackSlash;
                Dec(FIndex, Integer(FString[FIndex] <> cnstBackSlash));
              end;
            cnstVertSlash:
              Dec(FIndex, Integer(FString[FIndex] = cnstVertSlash));
          end;
      end;
    end;
  end;

  procedure SetupLastOptions;
  var
    vTextBase: TsgDXFText;
    vFontStyle: TmvFontStyle;
  begin
    vIndexTextModel := -1;
    if FLevels.Count > 0 then
      vIndexTextModel := FLevels.Last;
    if (vIndexTextModel > -1) and (not vSetupLastOptions) and
      (vIndexTextModel < FDest.Count) then
    begin
      vTextBase := TsgDXFText(FDest.Entities[vIndexTextModel]);
      AText.Height := vTextBase.Height;
      AText.Scale := vTextBase.Scale; // vTextBase.Style.WidthFactor;
      AText.Layer := vTextBase.Layer;
      AText.WinFont := vTextBase.WinFont;
      AText.Height := vTextBase.Height;
      AText.FVAlign := vTextBase.FVAlign;
      AText.FHAlign := vTextBase.FHAlign;
      AText.ObliqueAngle := vTextBase.ObliqueAngle;
      AText.FHAlign := vTextBase.FHAlign;
      AText.ColorCAD := vTextBase.ColorCAD;
      AText.Font.Name := vTextBase.Font.Name;
      AText.Properties.FFontName := vTextBase.Properties.FFontName;
      AText.UseDefaultFontName := vTextBase.UseDefaultFontName;
      vSetupLastOptions := True;
      for vFontStyle := Low(TmvFontStyle) to High(TmvFontStyle) do
        if vFontStyle in vTextBase.Font.Style then
          AText.Font.Style := AText.Font.Style + [vFontStyle]
        else
          AText.Font.Style := AText.Font.Style - [vFontStyle];
    end;
  end;

  function IsLastOnlySpace: Boolean;
  var
    I, vIndexLevelText: Integer;
    vStr: string;
  begin
    Result := False;
    if FLevels.Count > 0 then
    begin
      Result := True;
      vIndexLevelText := FLevels.Last;
      if FDest.Count < vIndexLevelText then
        vIndexLevelText := FDest.Count;
      if vIndexLevelText < FDest.Count then
        vStr := TsgDXFText(FDest[vIndexLevelText]).Text;
      for I := 1 to Length(vStr) do
        if vStr[I] <> cnstSpace then
        begin
          Result := False;
          Break;
        end;
    end;
  end;

var
  vIndex: Integer;
begin
  // FCarryCount := 0;
  AText := CreateDefaultText;
  vSetupLastOptions := False;
  vDone := False;
  vIsChangeLevel := False;
  vReadTextOption := False;
  if FLevels.Count > 0 then
  begin
    vIndex := FLevels.Last;
    if (vIndex < FDest.Count) and FNeedSetupOptions then
    begin
      SetupLastOptions;
      FNeedSetupOptions := False;
    end;
  end;
  while (FIndex <= FLength) and (AText.FTextParse^.TextPos = csNone) and
    not(vDone) do
  begin
    case FString[FIndex] of
      cnstBackSlash, cnstVertSlash:
        begin
          if Length(AText.FText) = 0 then
          begin
            SetupLastOptions;
            PMakeTextOption;
          end
          else
          begin
            if (FIndex < FLength) and (FString[FIndex + 1] <> cnstBackSlash)
            then
            begin
              if not vIsChangeLevel then
              begin
                vIsChangeLevel := True;
                if not IsLastOnlySpace then
                  FLevels.Add(FDest.Count)
                else
                  FLevels.Last := FDest.Count;
              end;
              Break;
            end
            else
            begin
              Inc(FIndex);
              AText.FText := AText.FText + cnstBackSlash;
            end;
          end;
        end;
      cnstCommaPoint:
        begin
          // FText :='';
          if vReadTextOption then
            vReadTextOption := False
          else
            AText.FText := AText.FText + FString[FIndex];
        end;
      cnstLeftBracket:
        begin
          if Length(AText.FText) > 0 then
            Break
          else
          begin
            if FIndex > 1 then
            begin
              SetupLastOptions;
              if not vIsChangeLevel then
              begin
                vIsChangeLevel := True;
                FLevels.Add(FDest.Count);
              end;
            end;
          end
        end;
      cnstRigthBracket:
        begin
          Inc(FIndex);
          if FLevels.Count > 0 then
            FLevels.Delete(FLevels.Count - 1);
          Break;
        end;
      cnstCaret:
        begin
          if FLength >= (FIndex + 1) then
          begin
            case FString[FIndex + 1] of
              'i', 'j', 'I', 'J':
                begin
                  if Length(AText.FText) = 0 then
                  begin
                    Inc(FIndex);
                    if (FString[FIndex] = 'j') or (FString[FIndex] = 'J') then
                    begin
                      AText.FPoint.X := 0;
                      AText.FPoint1.X := 0;
                    end
                    else
                      Inc(AText.FTextParse^.ParagraphParams.T);
                  end
                  else
                    Break;
                end;
            else
              if AText.FTextParse^.TwiddleCount = 0 then
                AText.FText := AText.FText + FString[FIndex]
              else
                Break;
            end;
          end;
        end;
      cnstPercent:
        begin
          if (FCells <> nil) and (FIndex + 2 <= FLength) and
            (FString[FIndex + 1] = '%') and
            ((FString[FIndex + 2] = 'v') or (FString[FIndex + 2] = 'V')) then
          begin
            if Length(AText.FText) = 0 then
            begin
              FHasLine := True;
              Inc(FIndex, 3);
            end;
            Break;
          end
          else if AText.FTextParse^.TwiddleCount = 0 then
            AText.FText := AText.FText + FString[FIndex]
          else
            Break;
        end;
    else
      if AText.FTextParse^.TwiddleCount = 0 then
        AText.FText := AText.FText + FString[FIndex]
      else
        Break;
    end;
    Inc(FIndex);
  end;
  if not vSetupLastOptions then
    SetupLastOptions;
end;

procedure TsgMTextParser.SetIsFirstTextAndLoad(const AText: TsgDXFText);
begin
  FLenByRow := 0;
  AText.FTextParse^.ParagraphParams.IsFirstText := True;
  AText.FPoint.X := 0;
  AText.FPoint1.X := 0;
  AText.FPoint1.Y := 0;
  AText.Loaded(FConverter);
end;

procedure TsgMTextParser.SpliteTextbySpace(const AEntities: TsgDXFEntity;
  AStart: Integer);
var
  vTextBase, vTextNew: TsgDXFText;
  vBeginSpace, vEndSpace: Integer;
  vStr: string;
begin
  while AStart < AEntities.Count do
  begin
    vTextBase := TsgDXFText(AEntities[AStart]);
    Inc(AStart);
    vStr := vTextBase.Text;
    vBeginSpace := StringScan(' ', vStr, 1);
    if vBeginSpace > 0 then
    begin
      vEndSpace := vBeginSpace + 1;
      while (vEndSpace <= Length(vStr)) and (vStr[vEndSpace] = ' ') do
        Inc(vEndSpace);
      vTextBase.Text := Copy(vStr, 1, vEndSpace - 1);
      vTextBase.Loaded(FConverter);
      if vEndSpace < Length(vStr) then
      begin
        vTextNew := TsgDXFText.Create;
        if AStart >= AEntities.Count then
          AEntities.AddEntity(vTextNew)
        else
          AEntities.InsertEntity(AStart, vTextNew);
        vTextNew.CreateTextParse;
        CopyTextOptions(vTextBase, vTextNew);
        vTextNew.Point := MakeFPoint(vTextBase.Box.Right, vTextBase.Point.Y,
          vTextBase.Point.Z);
        vTextNew.Point1 := vTextNew.FPoint;
        vTextNew.Text := Copy(vStr, vEndSpace, Length(vStr) - vEndSpace + 1);
        vTextNew.Loaded(FConverter);
      end;
    end;
  end;
end;

function TsgMTextParser.GetTextTab(const AText: TsgDXFText): Double;
var
  vFirstTab, vTabCnt, vIndex: Integer;
  vTab, vTabSize, vTabIndex, vTabFirst: Double;
  vIsHasFirstTab, vFind: Boolean;

  function GetTab(const AIndex: Integer): Double;
  begin
    vFind := True;
    if AIndex = 0 then
    begin
      if vIsHasFirstTab then
        Result := vTabFirst
      else if AText.FTextParse^.ParagraphParams.TabsCount > 0 then
        Result := AText.FTextParse^.ParagraphParams.Tabs[0]
      else
        Result := vTabSize;
    end
    else
    begin
      if AIndex - Integer(vIsHasFirstTab) < AText.FTextParse^.ParagraphParams.TabsCount
      then
        Result := AText.FTextParse^.ParagraphParams.Tabs
          [AIndex - Integer(vIsHasFirstTab)]
      else
      begin
        vFind := False;
        Result := 0;
      end;
    end;
  end;

begin
  Result := AText.FTextParse^.Offset.X;
  if AText.FTextParse^.ParagraphParams.T > 0 then
  begin
    vTabSize := 4 * FSource.FHeight;
    if AText.FTextParse^.ParagraphParams.I < 0 then
      vTabFirst := Abs(AText.FTextParse^.ParagraphParams.I)
    else
      vTabFirst := Abs(AText.FTextParse^.ParagraphParams.L);
    vIsHasFirstTab := (vTabFirst > 0);
    vFirstTab := 0;
    vFind := False;
    while vFirstTab < AText.FTextParse^.ParagraphParams.TabsCount +
      Integer(vIsHasFirstTab) do
    begin
      vTab := GetTab(vFirstTab);
      if vFind and (vTab < AText.FPoint1.X) then
      begin
        vFind := False;
        Inc(vFirstTab);
      end
      else
        Break;
    end;
    if vFind then
      Result := GetTab(vFirstTab + AText.FTextParse^.ParagraphParams.T - 1);
    if not vFind then
    begin
      if (AText.FTextParse^.ParagraphParams.TabsCount > 0) and
        (AText.FTextParse^.ParagraphParams.Tabs
        [AText.FTextParse^.ParagraphParams.TabsCount - 1] > AText.FPoint1.X)
      then
      begin
        vIndex := AText.FTextParse^.ParagraphParams.TabsCount;
        vTabIndex := vTabSize * Round(AText.FTextParse^.ParagraphParams.Tabs
          [vIndex - 1] / vTabSize);
        vTabCnt := AText.FTextParse^.ParagraphParams.T - vIndex -
          Integer(vIsHasFirstTab);
        Result := (vTabCnt + Integer(vTabCnt = 0)) * vTabSize + vTabIndex;
      end
      else
      begin
        vIndex := Floor(AText.FPoint1.X / vTabSize) +
          AText.FTextParse^.ParagraphParams.T;
        Result := vIndex * vTabSize;
      end;
    end;
  end;
end;

function TsgMTextParser.GetTextWidth(const AText: Pointer): Double;
begin
  Result := TsgDXFText(AText).Box.Right - TsgDXFText(AText).Point.X;
end;

function TsgMTextParser.GetDestWidth: Double;
var
  vText: TsgDXFText;
  vLeft, vRight: Double;
  I: Integer;
begin
  vLeft := cnstBadRect.Left;
  vRight := cnstBadRect.Right;
  for I := FDest.Count - 1 downto 0 do
  begin
    vText := TsgDXFText(FDest.Entities[I]);
    if vLeft > vText.FBox.Left then
      vLeft := vText.FBox.Left;
    if vLeft > vText.FBox.Right then
      vLeft := vText.FBox.Right;
    if vRight < vText.FBox.Left then
      vRight := vText.FBox.Left;
    if vRight < vText.FBox.Right then
      vRight := vText.FBox.Right;
  end;
  Result := vRight - vLeft;
end;

function TsgMTextParser.GetTextHeight(const AText: TsgDXFText): Double;
begin
  Result := AText.FTextParse^.FontParams.Above +
    AText.FTextParse^.FontParams.Below;
end;

function TsgMTextParser.GetBoxWidth(const AText: TsgDXFText): Double;
begin
  Result := AText.FBox.Right - AText.FBox.Left;
end;

function TsgMTextParser.IsFirstText(const AText: Pointer): Boolean;
begin
  Result := TsgDXFText(AText).FTextParse^.ParagraphParams.IsFirstText;
end;

function TsgMTextParser.IsTextEmpty(const AText: TsgDXFText): Boolean;
begin
  Result := (Length(AText.FText) = 0) and (Length(AText.FUnicodeText) = 0);
end;

{ Tsg2DCurve }

constructor Tsg2DCurve.Create;
begin
  inherited Create;
end;

function Tsg2DCurve.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
end;

procedure Tsg2DCurve.Assign(const AVal: Tsg2DCurve);
begin
end;

procedure Tsg2DCurve.ClearPoints;
begin
end;

function Tsg2DCurve.GetCount: Integer;
begin
  Result := 0;
end;

function Tsg2DCurve.GetEndPoint: TF2DPoint;
begin
  Result := cnstF2DPointZero;
end;

function Tsg2DCurve.GetEdgeType: Byte;
begin
  Result := cnst2DCurveUndefined;
end;

function Tsg2DCurve.GetPoints(const AIndex: Integer): TF2DPoint;
begin
  Result := cnstF2DPointZero;
end;

function Tsg2DCurve.GetStartPoint: TF2DPoint;
begin
  Result := cnstF2DPointZero;
end;

function Tsg2DCurve.IsEdgeEqual(const ACurve: Tsg2DCurve): Boolean;
begin
  Result := EdgeType = ACurve.EdgeType;
end;

procedure Tsg2DCurve.Loaded;
begin
end;

procedure Tsg2DCurve.Reverse(ANeedLoad: Boolean);
begin
end;

{ Tsg2DPoints }

procedure Tsg2DPoints.Assign(const AVal: Tsg2DCurve);
begin
  ClearPoints;
  inherited Assign(AVal);
end;

procedure Tsg2DPoints.ClearPoints;
begin
  FreeAndNil(FPoints);
end;

destructor Tsg2DPoints.Destroy;
begin
  FreeAndNil(FPoints);
  inherited Destroy;
end;

function Tsg2DPoints.GetCount: Integer;
begin
  Result := GetPointsCount;
end;

function Tsg2DPoints.GetEndPoint: TF2DPoint;
begin
  if GetPointsCount > 0 then
    Result := FPoints.Last
  else
    Result := inherited GetEndPoint;
end;

function Tsg2DPoints.GetPointsCount: Integer;
begin
  Result := 0;
  if FPoints <> nil then
    Result := FPoints.Count;
end;

function Tsg2DPoints.GetPoints(const AIndex: Integer): TF2DPoint;
begin
  if GetPointsCount > 0 then
    Result := FPoints[AIndex]
  else
    Result := inherited GetPoints(AIndex);
end;

function Tsg2DPoints.GetStartPoint: TF2DPoint;
begin
  if GetPointsCount > 0 then
    Result := FPoints.First
  else
    Result := inherited GetStartPoint;
end;

procedure Tsg2DPoints.Loaded;
begin
  inherited Loaded;
  ClearPoints;
  if FPoints = nil then
  begin
    FPoints := TF2DPointList.Create;
    FPoints.Capacity := MaxI(Count, 4);
  end;
end;

{ Tsg2DArc }

constructor Tsg2DArc.Create;
begin
  inherited Create;
  FPoints := nil;
end;

destructor Tsg2DArc.Destroy;
begin
  ClearPoints;
  inherited Destroy;
end;

function Tsg2DArc.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlCenterPoint:
      FCenterPoint := MakeF2DPointFrom3D(ANode.ValueAsFPoint);
    xmlEndParam:
      FEndParam := ANode.ValueAsDouble;
    xmlRadius:
      FRadius := ANode.ValueAsDouble;
    xmlStartParam:
      FStartParam := ANode.ValueAsDouble;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure Tsg2DArc.Assign(const AVal: Tsg2DCurve);
var
  vArc: Tsg2DArc absolute AVal;
begin
  inherited Assign(AVal);
  if AVal is Tsg2DArc then
  begin
    FCenterPoint := vArc.FCenterPoint;
    FFlag := vArc.FFlag;
    FEndParam := vArc.FEndParam;
    FRadius := vArc.FRadius;
    FStartParam := vArc.FStartParam;
  end;
end;

function Tsg2DArc.GetCounterClockWise: Boolean;
begin
  Result := FFlag and 1 <> 0;
end;

function Tsg2DArc.GetEdgeType: Byte;
begin
  Result := cnst2DCurveArc;
end;

function Tsg2DArc.GetParamByAngle(const Angle: Double): Double;
begin
  Result := Angle;
end;

function Tsg2DArc.GetCount: Integer;
begin
  Result := GetNumberOfCircleParts + 1;
end;

function Tsg2DArc.IsEdgeEqual(const ACurve: Tsg2DCurve): Boolean;
var
  vArc: Tsg2DArc absolute ACurve;
begin
  Result := False;
  if inherited IsEdgeEqual(ACurve) then
  begin
    Result := (FFlag = vArc.FFlag) and IsEqualF2DPoints(FCenterPoint,
      vArc.FCenterPoint) and IsEqual(FRadius, vArc.FRadius) and
      IsEqual(FStartParam, vArc.FStartParam) and IsEqual(FRadius, vArc.FRadius)
      and IsEqual(FEndParam, vArc.FEndParam);
  end;
end;

procedure Tsg2DArc.Loaded;
var
  vAngle: Double;
  A, B, ASin, ACos, X, Y, Angle, vStartParam, vEndParam: Double;
  S, C: Extended;
  vPt: TF2DPoint;
  I, Cnt: Integer;
  vSign, vParam: Double;
begin
  inherited Loaded;
  vEndParam := FEndParam;
  vStartParam := FStartParam;
  if not CounterClockWise then
  begin
    vAngle := vEndParam;
    vEndParam := -vStartParam;
    vStartParam := -vAngle;
  end;
  vStartParam := sgMod(vStartParam, 360);
  vEndParam := sgMod(vEndParam, 360);
  Params(A, B, ASin, ACos);
  vStartParam := GetParamByAngle(vStartParam);
  vEndParam := GetParamByAngle(vEndParam);
  if (vEndParam < vStartParam) or IsEqual(vEndParam, vStartParam,
    fDoubleResolution { fExtendedResolution } ) then
    vEndParam := vEndParam + 360;
  Cnt := Count - 1;
  vStartParam := vStartParam * fPiDividedBy180;
  vEndParam := vEndParam * fPiDividedBy180;
  Angle := (vEndParam - vStartParam) / Cnt;
  if not CounterClockWise then
  begin
    vSign := -1;
    vParam := vEndParam;
  end
  else
  begin
    vSign := 1;
    vParam := vStartParam;
  end;
  for I := 0 to Cnt do
  begin
    SinCos(vParam, S, C);
    vParam := vParam + vSign * Angle;
    X := A * C;
    Y := B * S;
    vPt.X := FCenterPoint.X + X * ACos - Y * ASin;
    vPt.Y := FCenterPoint.Y + X * ASin + Y * ACos;
    FPoints.Add(vPt);
  end;
end;

(* For future versions
  function Tsg2DArc.GetCount: Integer;
  begin
  if FPoints = nil then
  Result := iDefaultNumberOfCircleParts
  else
  Result := FPoints.Count;
  end;

  procedure Tsg2DArc.Loaded;
  var
  vAngle: Double;
  A, B, ASin, ACos, X, Y, Angle, vStartParam, vEndParam: Double;
  S, C: Extended;
  vPt: PF2DPoint;
  I, Cnt: Integer;

  function CheckParam(const AParam: Double): Double;
  var
  vParam: Double;
  Kd: Double;
  Ki: Integer;
  vMode: Integer;
  begin
  vParam := Abs(AParam);
  if AParam > fAccuracy then
  vMode := 1
  else
  if AParam < -fAccuracy then
  vMode := -1
  else
  vMode := 0;
  if vMode <> 0 then
  begin
  Kd := vParam / 360;
  Ki := Floor(Kd);
  if IsEqual(Kd, Ki) then
  begin
  if vMode > 0 then
  Result := 360
  else
  Result := 0;
  end
  else
  begin
  if vMode > 0 then
  Result := vParam - Ki * 360
  else
  Result := (Ki + 1) * 360 - vParam;
  end;
  end
  else
  Result := 0;
  end;

  begin
  ClearPoints;
  FPoints := TList.Create;
  vEndParam := FEndParam;
  vStartParam := FStartParam;
  if not CounterClockWise then
  begin
  vAngle := vEndParam;
  vEndParam := -vStartParam;
  vStartParam := -vAngle;
  end;
  vStartParam := CheckParam(vStartParam);
  vEndParam := CheckParam(vEndParam);
  Params(A, B, ASin, ACos);
  vStartParam := GetParamByAngle(vStartParam);
  vEndParam := GetParamByAngle(vEndParam);
  if (GetEdgeType = 2) and IsEqual(vEndParam, vStartParam) then
  begin
  SinCos(Radian(vStartParam), S, C);
  New(vPt);
  FPoints.Add(vPt);
  X := A * C;
  Y := B * S;
  vPt^.X := FCenterPoint.X + X * ACos - Y * ASin;
  vPt^.Y := FCenterPoint.Y + X * ASin + Y * ACos;
  end
  else
  begin
  FPoints.Capacity := iDefaultNumberOfCircleParts;
  if vEndParam <= vStartParam then
  vEndParam := vEndParam + 360;
  Cnt := iDefaultNumberOfCircleParts - 1;
  for I := 0 to Cnt do
  begin
  Angle := Radian(vStartParam + I * (vEndParam- vStartParam) / Cnt);
  SinCos(Angle, S, C);
  X := A * C;
  Y := B * S;
  New(vPt);
  FPoints.Add(vPt);
  vPt^.X := FCenterPoint.X + X * ACos - Y * ASin;
  vPt^.Y := FCenterPoint.Y + X * ASin + Y * ACos;
  end;
  end;
  end;
*)
procedure Tsg2DArc.Params(var A, B, ASin, ACos: Double);
begin
  A := FRadius;
  B := FRadius;
  ASin := 0;
  ACos := 1;
end;

procedure Tsg2DArc.Reverse(ANeedLoad: Boolean);
// var
// I, Cnt: Integer;
begin
  CounterClockWise := not CounterClockWise;
  SwapSGFloats(FStartParam, FEndParam);
  FStartParam := 360 - FStartParam;
  FEndParam := 360 - FEndParam;
  if ANeedLoad then
    Loaded
    // else
    // begin
    // Cnt := FPoints.Count;
    // for I := 0 to Cnt div 2 - 1 do
    // SwapPointers(FPoints.List^[I], FPoints.List^[Cnt - I - 1]);
    // end;
end;

procedure Tsg2DArc.SetCounterClockWise(const AVal: Boolean);
begin
  FFlag := (FFlag and 254) or Byte(AVal);
end;

function Tsg2DArc.ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = []
  ): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlCenterPoint].Name).ValueAsFPoint :=
    MakeFPointFrom2D(FCenterPoint);
  ANode.AddAttribNV(cnstXMLNames[xmlEndParam].Name).ValueAsDouble := FEndParam;
  ANode.AddAttribNV(cnstXMLNames[xmlRadius].Name).ValueAsDouble := FRadius;
  ANode.AddAttribNV(cnstXMLNames[xmlStartParam].Name).ValueAsDouble :=
    FStartParam;
end;

{ Tsg2DEllipse }

constructor Tsg2DEllipse.Create;
begin
  inherited Create;
  IsAngleInParam := True;
end;

function Tsg2DEllipse.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlMajorPoint:
      FMajorPoint := MakeF2DPointFrom3D(ANode.ValueAsFPoint);
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure Tsg2DEllipse.Assign(const AVal: Tsg2DCurve);
begin
  inherited Assign(AVal);
  if AVal is Tsg2DEllipse then
    FMajorPoint := Tsg2DEllipse(AVal).FMajorPoint;
end;

function Tsg2DEllipse.GetEdgeType: Byte;
begin
  Result := cnst2DCurveEllipse;
end;

function Tsg2DEllipse.GetIsAngleInParam: Boolean;
begin
  Result := FFlag and 2 <> 0;
end;

function Tsg2DEllipse.GetParamByAngle(const Angle: Double): Double;
var
  vTan: Double;
  S, C: Extended;
begin
  if IsAngleInParam then
  begin
    SinCos(Radian(Angle), S, C);
    if Abs(C) > fAccuracy then
    begin
      vTan := S / C;
      Result := Degree(ArcTan(vTan / FRadius));
      case Integer(S < 0) shl 1 + Integer(C < 0) of
        1, 3:
          begin
            Result := Result + 180;
            Result := Result - 360 * Floor(Result / 360);
          end;
      end;
    end
    else
      Result := Angle;
  end
  else
    Result := Angle;
end;

function Tsg2DEllipse.IsEdgeEqual(const ACurve: Tsg2DCurve): Boolean;
var
  vEllipse: Tsg2DEllipse absolute ACurve;
begin
  Result := False;
  if inherited IsEdgeEqual(ACurve) then
    Result := IsEqualF2DPoints(FMajorPoint, vEllipse.FMajorPoint);
end;

procedure Tsg2DEllipse.Params(var A, B, ASin, ACos: Double);
var
  S, C: Extended;
  vRot: Double;
begin
  A := Sqrt(Sqr(FMajorPoint.X) + Sqr(FMajorPoint.Y));
  B := A * FRadius;
  vRot := ArcTan2(FMajorPoint.Y, FMajorPoint.X);
  SinCos(vRot, S, C);
  ASin := S;
  ACos := C;
end;

procedure Tsg2DEllipse.Reverse(ANeedLoad: Boolean);
begin
end;

procedure Tsg2DEllipse.SetIsAngleInParam(const AVal: Boolean);
begin
  FFlag := (FFlag and 253) or (Byte(AVal) shl 1);
end;

function Tsg2DEllipse.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlMajorPoint].Name).ValueAsFPoint :=
    MakeFPointFrom2D(FMajorPoint);
end;

{ Tsg2DLine }

procedure Tsg2DLine.Assign(const AVal: Tsg2DCurve);
var
  vLine: Tsg2DLine absolute AVal;
begin
  inherited Assign(AVal);
  if AVal is Tsg2DLine then
  begin
    FEndPoint := vLine.FEndPoint;
    FStartPoint := vLine.FStartPoint;
  end;
end;

function Tsg2DLine.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlStartPoint:
      FStartPoint := MakeF2DPointFrom3D(ANode.ValueAsFPoint);
    xmlEndPoint:
      FEndPoint := MakeF2DPointFrom3D(ANode.ValueAsFPoint);
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function Tsg2DLine.GetCount: Integer;
begin
  Result := 2;
end;

function Tsg2DLine.GetEndPoint: TF2DPoint;
begin
  Result := FEndPoint;
end;

function Tsg2DLine.GetEdgeType: Byte;
begin
  Result := cnst2DCurveLine;
end;

function Tsg2DLine.GetPoints(const AIndex: Integer): TF2DPoint;
begin
  if AIndex = 0 then
    Result := FStartPoint
  else
    Result := FEndPoint;
end;

function Tsg2DLine.GetStartPoint: TF2DPoint;
begin
  Result := FStartPoint;
end;

procedure Tsg2DLine.Reverse(ANeedLoad: Boolean);
begin
  SwapF2DPoints(FStartPoint, FEndPoint);
  if ANeedLoad then
    Loaded;
end;

function Tsg2DLine.IsEdgeEqual(const ACurve: Tsg2DCurve): Boolean;
var
  vLine: Tsg2DLine absolute ACurve;
begin
  Result := False;
  if inherited IsEdgeEqual(ACurve) then
    Result := IsEqualF2DPoints(FStartPoint, vLine.FStartPoint) and
      IsEqualF2DPoints(FEndPoint, vLine.FEndPoint);
end;

procedure Tsg2DLine.SetEndPoint(const AVal: TF2DPoint);
begin
  FEndPoint := AVal;
end;

procedure Tsg2DLine.SetStartPoint(const AVal: TF2DPoint);
begin
  FStartPoint := AVal;
end;

function Tsg2DLine.ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = []
  ): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlStartPoint].Name).ValueAsFPoint :=
    MakeFPointFrom2D(FStartPoint);
  ANode.AddAttribNV(cnstXMLNames[xmlEndPoint].Name).ValueAsFPoint :=
    MakeFPointFrom2D(FEndPoint);
end;

{ Tsg2DPolyline }

procedure Tsg2DPolyline.Clear;
begin
  FVertexes.Count := 0;
  FreeAndNil(FBulges);
end;

constructor Tsg2DPolyline.Create;
begin
  inherited Create;
  FVertexes := TF2DPointList.Create;
  FBulges := nil;
end;

destructor Tsg2DPolyline.Destroy;
begin
  if FBulges <> nil then
    FBulges.Free;
  FVertexes.Free;
  ClearPoints;
  inherited Destroy;
end;

function Tsg2DPolyline.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  I, J: Integer;
  vNodeVertex: TsgNode;
  vAttrib: TsgNodeSample;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlClosed:
      Closed := ANode.ValueAsBool;
    xmlVertexes:
      begin
        Clear;
        vAttrib := ANode.GetAttributeByName(cnstXMLNames[xmlCount].Name);
        if Assigned(vAttrib) then
          FVertexes.Capacity := vAttrib.ValueAsInt;
        for I := 0 to ANode.ChildNodesCount - 1 do
        begin
          vNodeVertex := TsgNode(ANode.ChildNodes[I]);
          if GetXMLId(vNodeVertex.Name) = xmlVertex then
          begin
            for J := 0 to vNodeVertex.AttributeNodesCount - 1 do
            begin
              vAttrib := vNodeVertex.AttributeNodes[J];
              case GetXMLId(vAttrib.Name) of
                xmlPoint:
                  AddVertex(MakeF2DPointFrom3D(vAttrib.ValueAsFPoint));
                xmlBulge:
                  AddBulge(vAttrib.ValueAsDouble);
              end;
            end;
          end;
        end;
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure Tsg2DPolyline.AddBulge(const AVal: Single);
var
  I, Cnt: Integer;
begin
  if FBulges = nil then
  begin
    FBulges := TsgSingleList.Create;
    FBulges.Capacity := FVertexes.Count;
  end;
  I := FBulges.Count;
  Cnt := FVertexes.Count - 1;
  while I < Cnt do
  begin
    FBulges.Add(0);
    Inc(I);
  end;
  FBulges.Add(AVal);
end;

procedure Tsg2DPolyline.AddVertex(const APoint: TF2DPoint);
begin
  FVertexes.Add(APoint);
end;

procedure Tsg2DPolyline.ApplyBulge(const AP1, AP2: TF2DPoint;
  const ABulge: Double);
var
  vGenerator: TsgGeneratorShapeEdge;
begin
  vGenerator := TsgGeneratorShapeEdge.Create;
  try
    vGenerator.SetBaseList(FPoints);
    vGenerator.NumberCirclePart := GetNumberOfCircleParts;
    vGenerator.CreateBulgesArc(MakeFPointFrom2D(AP1),
      MakeFPointFrom2D(AP2), ABulge);
  finally
    vGenerator.Free;
  end;
end;

procedure Tsg2DPolyline.Assign(const AVal: Tsg2DCurve);
var
  vPoly: Tsg2DPolyline absolute AVal;
begin
  inherited Assign(AVal);
  if AVal is Tsg2DPolyline then
  begin
    FProps := vPoly.FProps;
    Clear;
    FVertexes.Assign(vPoly.FVertexes);
    if vPoly.FBulges <> nil then
    begin
      FBulges := TsgSingleList.Create;
      FBulges.Assign(vPoly.FBulges);
    end;
  end;
end;

function Tsg2DPolyline.GetBulge(const AIndex: Integer): Single;
begin
  if (FBulges <> nil) and (AIndex < FBulges.Count) then
    Result := FBulges[AIndex]
  else
    Result := 0;
end;

function Tsg2DPolyline.GetBulgesCount: Integer;
begin
  if FBulges <> nil then
    Result := FBulges.Count
  else
    Result := 0;
end;

function Tsg2DPolyline.GetClosed: Boolean;
begin
  Result := FProps and 1 <> 0;
end;

function Tsg2DPolyline.GetEdgeType: Byte;
begin
  Result := cnst2DCurvePoly;
end;

function Tsg2DPolyline.GetEndPoint: TF2DPoint;
begin
  if FVertexes.Count > 0 then
    Result := FVertexes.Last
  else
    Result := inherited GetEndPoint;
end;

function Tsg2DPolyline.GetHasBulge: Boolean;
begin
  Result := Assigned(FBulges) and (FBulges.Count > 0);
end;

function Tsg2DPolyline.GetLastVertex: PF2DPoint;
begin
  if FVertexes.Count > 0 then
    Result := @FVertexes.List[FVertexes.Count - 1]
  else
    Result := nil;
end;

function Tsg2DPolyline.GetVertex(const AIndex: Integer): TF2DPoint;
begin
  if AIndex < FVertexes.Count then
    Result := FVertexes[AIndex]
  else
    Result := cnstF2DPointZero;
end;

function Tsg2DPolyline.GetVertexesCount: Integer;
begin
  Result := FVertexes.Count;
end;

function Tsg2DPolyline.IsEdgeEqual(const ACurve: Tsg2DCurve): Boolean;
var
  vPoly: Tsg2DPolyline absolute ACurve;
begin
  Result := False;
  if inherited IsEdgeEqual(ACurve) then
  begin
    if (FProps = vPoly.FProps) then
    begin
      if not((FBulges = nil) xor (vPoly.FBulges = nil)) then
      begin
        if FBulges <> nil then
          Result := FBulges.IsEqual(vPoly.FBulges,
            TsgPointerTypeComparer.CmpSingle)
        else
          Result := True;
      end;
      if Result then
        Result := FPoints.IsEqual(vPoly.FPoints);
    end;
  end;
end;

procedure Tsg2DPolyline.Loaded;
var
  I, Cnt: Integer;
  P1, P2: TF2DPoint;
  vBulge: Single;
begin
  inherited Loaded;
  Cnt := FVertexes.Count - 1;
  for I := 0 to Cnt do
  begin
    P1 := FVertexes[I];
    vBulge := Bulges[I];
    if (vBulge <> 0) then
    begin
      if (I < Cnt) then
        P2 := FVertexes[I + 1]
      else
        P2 := FVertexes[0];
      ApplyBulge(P1, P2, vBulge);
    end
    else
      FPoints.Add(P1);
  end;
end;

procedure Tsg2DPolyline.SetBulge(const AIndex: Integer; const AVal: Single);
begin
  if (FBulges <> nil) and (AIndex < FBulges.Count) then
    FBulges[AIndex] := AVal;
end;

procedure Tsg2DPolyline.SetClosed(const AVal: Boolean);
begin
  FProps := (FProps and 254) or Byte(AVal);
end;

procedure Tsg2DPolyline.SetVertex(const AIndex: Integer;
  const APoint: TF2DPoint);
begin
  if AIndex < FVertexes.Count then
    FVertexes[AIndex] := APoint;
end;

function Tsg2DPolyline.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
var
  I: Integer;
  vBulge: Single;
  vNodeVertex, vNodeVertexes: TsgNode;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlClosed].Name).ValueAsBool := Closed;
  vNodeVertexes := ANode.AddChildNV(cnstXMLNames[xmlVertexes].Name);
  vNodeVertexes.AddAttribNV(cnstXMLNames[xmlCount].Name).ValueAsInt :=
    VertexesCount;
  if IsXMLHelp(AMode) and (VertexesCount = 0) then
  begin
    vNodeVertex := vNodeVertexes.AddChildNV(cnstXMLNames[xmlVertex].Name);
    vNodeVertex.AddAttribNV(cnstXMLNames[xmlPoint].Name).ValueAsFPoint :=
      cnstFPointZero;
    vNodeVertex.AddAttribNV(cnstXMLNames[xmlBulge].Name).ValueAsDouble := 0;
  end
  else
  begin
    for I := 0 to VertexesCount - 1 do
    begin
      vNodeVertex := vNodeVertexes.AddChildNV(cnstXMLNames[xmlVertex].Name);
      vNodeVertex.AddAttribNV(cnstXMLNames[xmlPoint].Name).ValueAsFPoint :=
        MakeFPointFrom2D(Vertexes[I]);
      vBulge := Bulges[I];
      if IsFullPropsOrXMLHelp(AMode) or (vBulge <> 0) then
        vNodeVertex.AddAttribNV(cnstXMLNames[xmlBulge].Name).ValueAsDouble
          := vBulge;
    end;
  end;
end;

{ Tsg2DSpline }

constructor Tsg2DSpline.Create;
begin
  inherited Create;
  FControls := TF2DPointList.Create;
  FKnots := TsgSingleList.Create;
  FPoints := nil;
end;

destructor Tsg2DSpline.Destroy;
begin
  FKnots.Free;
  FControls.Free;
  FWeights.Free;
  ClearPoints;
  inherited Destroy;
end;

function Tsg2DSpline.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlDegree:
      Degree := ANode.ValueAsInt;
    xmlPeriodic:
      Periodic := ANode.ValueAsBool;
    xmlRational:
      Rational := ANode.ValueAsBool;
    xmlControlPoints:
      FControls.FromXML(ANode { , AResult } );
    xmlKnotsPoints:
      FKnots.FromXML(ANode { , AResult } );
    xmlWeights:
      begin
        if not Assigned(FWeights) then
          FWeights := TsgSingleList.Create;
        FWeights.FromXML(ANode { , AResult } );
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure Tsg2DSpline.AddControl(const APoint: TF2DPoint);
begin
  FControls.Add(APoint);
end;

procedure Tsg2DSpline.AddKnot(const AVal: Single);
begin
  FKnots.Add(AVal);
end;

procedure Tsg2DSpline.AddWeight(const AVal: Single);
begin
  if FWeights = nil then
    FWeights := TsgSingleList.Create;
  FWeights.Add(AVal);
end;

function Tsg2DSpline.GetLastVertex: PF2DPoint;
begin
  if FControls.Count > 0 then
    Result := @FControls.List[FControls.Count - 1]
  else
    Result := nil;
end;

procedure Tsg2DSpline.Assign(const AVal: Tsg2DCurve);
var
  vSpline: Tsg2DSpline absolute AVal;
begin
  inherited Assign(AVal);
  if AVal is Tsg2DSpline then
  begin
    FParams := vSpline.FParams;
    FControls.Assign(vSpline.FControls);
    FKnots.Assign(vSpline.FKnots);
    FreeAndNil(FWeights);
    if vSpline.FWeights <> nil then
    begin
      FWeights := TsgSingleList.Create;
      FWeights.Assign(vSpline.FWeights);
    end;
  end;
end;

function Tsg2DSpline.GetDegree: Byte;
begin
  Result := FParams and 255;
end;

function Tsg2DSpline.GetEdgeType: Byte;
begin
  Result := cnst2DCurveSpline;
end;

function Tsg2DSpline.GetKnot(const AIndex: Integer): Single;
begin
  if AIndex < FKnots.Count then
    Result := FKnots[AIndex]
  else
    Result := 0;
end;

function Tsg2DSpline.GetPeriodic: Boolean;
begin
  Result := FParams and $200 <> 0;
end;

function Tsg2DSpline.GetRational: Boolean;
begin
  Result := FParams and $100 <> 0;
end;

function Tsg2DSpline.GetWeight(const AIndex: Integer): Single;
begin
  if AIndex < WeightsCount then
    Result := FWeights[AIndex]
  else
    Result := 0;
end;

function Tsg2DSpline.GeWeightsCount: Integer;
begin
  Result := 0;
  if Assigned(FWeights) then
    Result := FWeights.Count;
end;

function Tsg2DSpline.IsEdgeEqual(const ACurve: Tsg2DCurve): Boolean;
var
  vSpline: Tsg2DSpline absolute ACurve;
begin
  Result := False;
  if inherited IsEdgeEqual(ACurve) then
  begin
    if not((FKnots = nil) xor (vSpline.FKnots = nil)) then
    begin
      if FKnots <> nil then
        Result := FKnots.IsEqual(vSpline.FKnots,
          TsgPointerTypeComparer.CmpSingle)
      else
        Result := True;
    end;
    if Result then
      Result := FControls.IsEqual(vSpline.FControls,
        TsgPointerTypeComparer.CmpF2DPoint);
  end;
end;

procedure Tsg2DSpline.Loaded;
var
  vGenerator: TsgGeneratorShapeEdge;
  vWeights: TsgSingleList;
begin
  inherited Loaded;
  vGenerator := TsgGeneratorShapeEdge.Create;
  try
    vGenerator.NumberSplinePart := GetNumberOfSplineParts;
    vGenerator.SetBaseList(FPoints);
    if vGenerator.IsBSpline(Degree) then
    begin
      vWeights := nil;
      if Rational then
        vWeights := FWeights;
      vGenerator.CreateBSpline(FControls, FKnots, vWeights, Degree);
    end
    else
      vGenerator.CreateSplineByKnots(FControls, FKnots,
        1 / vGenerator.NumberSplinePart);
  finally
    vGenerator.Free;
  end;
end;

function Tsg2DSpline.GetControl(const AIndex: Integer): TF2DPoint;
begin
  if AIndex < FControls.Count then
    Result := FControls[AIndex]
  else
    Result := cnstF2DPointZero;
end;

function Tsg2DSpline.GetControlsCount: Integer;
begin
  Result := FControls.Count;
end;

function Tsg2DSpline.GetKnotsCount: Integer;
begin
  Result := FKnots.Count;
end;

procedure Tsg2DSpline.SetControl(const AIndex: Integer;
  const APoint: TF2DPoint);
begin
  if AIndex < FControls.Count then
    FControls[AIndex] := APoint;
end;

procedure Tsg2DSpline.SetDegree(const Value: Byte);
begin
  FParams := (FParams and $FFFFFF00) or Value;
end;

procedure Tsg2DSpline.SetKnot(const AIndex: Integer; const AVal: Single);
begin
  if AIndex < FKnots.Count then
    FKnots[AIndex] := AVal;
end;

procedure Tsg2DSpline.SetPeriodic(const Value: Boolean);
begin
  FParams := (FParams and $FFFFFDFF) or (Cardinal(Value) shl 9);
end;

procedure Tsg2DSpline.SetRational(const Value: Boolean);
begin
  FParams := (FParams and $FFFFFEFF) or (Cardinal(Value) shl 8);
end;

procedure Tsg2DSpline.SetWeight(const AIndex: Integer; const Value: Single);
begin
  if AIndex < WeightsCount then
    FWeights[AIndex] := Value;
end;

function Tsg2DSpline.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
var
  vNodeControls, vNodeKnots, vNodeWeights: TsgNode;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlDegree].Name).ValueAsInt := Degree;
  ANode.AddAttribNV(cnstXMLNames[xmlPeriodic].Name).ValueAsBool := Periodic;
  ANode.AddAttribNV(cnstXMLNames[xmlRational].Name).ValueAsBool := Rational;
  if (ControlsCount > 0) or IsXMLHelp(AMode) then
  begin
    vNodeControls := ANode.AddChildNV(cnstXMLNames[xmlControlPoints].Name);
    if ControlsCount > 0 then
      FControls.ToXML(vNodeControls, cnstXMLNames[xmlPoint].Name);
  end;
  if (KnotsCount > 0) or IsXMLHelp(AMode) then
  begin
    vNodeKnots := ANode.AddChildNV(cnstXMLNames[xmlKnotsPoints].Name);
    if KnotsCount > 0 then
      FKnots.ToXML(vNodeKnots, cnstXMLNames[xmlKnot].Name);
  end;
  if (WeightsCount > 0) or IsXMLHelp(AMode) then
  begin
    vNodeWeights := ANode.AddChildNV(cnstXMLNames[xmlWeights].Name);
    if WeightsCount > 0 then
      FWeights.ToXML(vNodeWeights, cnstXMLNames[xmlWeight].Name);
  end;
end;

{ Tsg2DBoundaryList }

procedure Tsg2DBoundaryList.Clear;
begin
  ClearList(FObjects);
end;

procedure Tsg2DBoundaryList.CopyFrom(const AList: Tsg2DBoundaryList;
  const AIndex, ACount: Integer);
begin
  FObjects.Capacity := ACount;
  FObjects.Count := FObjects.Capacity;
  CopyMemory(FObjects.List, @AList.FObjects.List[AIndex],
    ACount * SizeOf(Pointer));
end;

constructor Tsg2DBoundaryList.Create;
begin
  inherited Create;
  FBoundaryType := 1;
  FObjects := TList.Create;
end;

procedure Tsg2DBoundaryList.Delete(const AIndex: Integer);
begin
  FObjects.Delete(AIndex);
end;

destructor Tsg2DBoundaryList.Destroy;
begin
  Clear;
  FObjects.Free;
  inherited Destroy;
end;

function Tsg2DBoundaryList.GetCount: Integer;
begin
  Result := FObjects.Count;
end;

function Tsg2DBoundaryList.GetItem(const AIndex: Integer): Tsg2DCurve;
begin
  Result := FObjects.List[AIndex];
end;

function Tsg2DBoundaryList.IsTextBox: Boolean;
begin
  Result := FBoundaryType and 8 <> 0;
end;

procedure Tsg2DBoundaryList.SetCount(const AValue: Integer);
begin
  FObjects.Count := AValue;
end;

procedure Tsg2DBoundaryList.SetItem(const AIndex: Integer;
  const AValue: Tsg2DCurve);
begin
  FObjects.List[AIndex] := AValue;
end;

procedure Tsg2DBoundaryList.Add(const AValue: Tsg2DCurve);
begin
  FObjects.Add(AValue);
end;

procedure Tsg2DBoundaryList.AssignBoundary(const AObject: TObject);
type
  Tsg2DCurveClass = class of Tsg2DCurve;
var
  I: Integer;
  vObjects: TList;
  vCurve: Tsg2DCurve;
begin
  vObjects := nil;
  Clear;
  if AObject is Tsg2DBoundaryList then
  begin
    FBoundaryType := Tsg2DBoundaryList(AObject).FBoundaryType;
    vObjects := Tsg2DBoundaryList(AObject).FObjects;
  end
  else
  begin
    if AObject is TList then
    begin
      FBoundaryType := 0;
      vObjects := TList(AObject);
    end;
  end;
  if (vObjects <> nil) and (vObjects.Count > 0) then
  begin
    FObjects.Capacity := vObjects.Count;
    for I := 0 to vObjects.Count - 1 do
    begin
      vCurve := Tsg2DCurveClass(Tsg2DCurve(vObjects[I]).ClassType).Create;
      FObjects.Add(vCurve);
      vCurve.Assign(vObjects[I]);
    end;
  end;
end;

procedure Tsg2DBoundaryList.Insert(const AIndex: Integer;
  const AValue: Tsg2DCurve);
begin
  FObjects.Insert(AIndex, AValue);
end;

function Tsg2DBoundaryList.IsBoundaryEqual(const AList
  : Tsg2DBoundaryList): Boolean;
  function ProcEqualCurves(const Value1, Value2: Pointer): Boolean;
  begin
    Result := Tsg2DCurve(Value1).IsEdgeEqual(Value2)
  end;

begin
  Result := False;
  if FBoundaryType = AList.FBoundaryType then
    Result := IsEqualListsEnum(Self.FObjects, AList.FObjects, @ProcEqualCurves);
end;

{ TsgDXFConverter }

function TsgDXFConverter.AddAttribsByBlock(const AIns: TsgDXFInsert;
  const ABlock: TsgDXFBlock): Boolean;
var
  I, Cnt: Integer;
  vAttrib: TsgDXFAttrib;
  vEnt: TsgDXFEntity;
  M: TFMatrix;
begin
  Result := False;
  M := AIns.GetMatrix;
  Cnt := ABlock.Count - 1;
  for I := 0 to Cnt do
  begin
    vEnt := ABlock.Entities[I];
    if vEnt.EntType = ceAttdef then
    begin
      vAttrib := TsgDXFAttrib.Create;
      AIns.AddEntity(vAttrib);
      vAttrib.AssignEntity(TsgDXFAttdef(vEnt));
      vAttrib.Point := FPointXMat(vAttrib.Point, M);
      Self.Loads(vAttrib);
      Result := True;
    end;
  end;
end;

constructor TsgDXFConverter.Create;
var
  vParam: TsgConverterParams;
begin
  FillChar(vParam, SizeOf(vParam), 0);
  CreateEx(vParam);
end;

procedure TsgDXFConverter.CreateXDataProcs(AClass: TsgClassXDataProcs = nil);
begin
{$IFDEF SG_BTI}
  if AClass = nil then
    AClass := DXFConv.GetClassXDataProcs;
  FreeAndNil(FXDataProcs);
  if AClass <> nil then
    FXDataProcs := AClass.Create;
{$ENDIF}
end;

function TsgDXFConverter.CreateDimStyles(const AppLanguage: TsgLangugeID;
  const ACreate: Boolean): TsgDXFDimensionStyle;
var
  I: Integer;
  vHeadVarStruct: PsgHeadVarStruct;
  vStyle: TsgDXFDimensionStyle;
begin
  vHeadVarStruct := PHeadVarStruct;
  if ACreate then
  begin
    vHeadVarStruct^.DimTextStyle := cnstActiveStyles[AppLanguage];
    Result := DimensionStyleByName(vHeadVarStruct^.TextStyle);
    for I := Low(cnstCadStyles) to High(cnstCadStyles) do
    begin
      if (cnstCadStyles[I].LangIds = []) or
        (AppLanguage in cnstCadStyles[I].LangIds) then
      begin
        vStyle := DimensionStyleByName(cnstCadStyles[I].Name);
        if cnstCadStyles[I].Name = vHeadVarStruct^.TextStyle then
          vStyle.InitProps(vHeadVarStruct);
        vStyle.TextStyle := StyleByName(vStyle.Name);
        if vStyle.Name = cnstGost then
        begin
          vStyle.DIMTIH := False;
          vStyle.DIMTOH := False;
          vStyle.TextPosVert := pvAbove;
        end;
        vStyle.Loaded(Self);
      end;
    end;
  end
  else
    Result := DimensionStyleByName(vHeadVarStruct^.DimStyle);
  if not Assigned(Result.TextStyle) then
    Result.TextStyle := StyleByName(vHeadVarStruct.DimTextStyle);
end;

procedure TsgDXFConverter.CreateEntitiesWithGeneratedHandles;
begin
  if not FMapEntities.HasGeneratedList then
    FMapEntities.CreateGeneratedList;
end;

constructor TsgDXFConverter.CreateEx(const AParams: TsgConverterParams);
var
  vPaths: TStringList;
  I: Integer;
  vFonstPaths: string;
  vLayout: TsgDXFLayout;
begin
  inherited Create;
  FConvExtended := TsgConverterExtented.Create(Self);
{$IFDEF CONV_REFCOUNT}
  FRefEnts := TsgList.Create;
  FRefEnts.Duplicates := dupIgnore;
  FRefEnts.Sorted := True;
{$ENDIF}
  FMapEntities := TsgMapEntities.Create(Self);
  FTotalACISLoading := 0;
  FileName := AParams.FileName;
  if AParams.CheckHandles then
    CreateEntitiesWithGeneratedHandles;
  FOnFindFont := GlobalFindFont;
  (*
    {$IFDEF DEMO}
    Application.MessageBox('CAD Import VCL demo - please register at www.cadsofttools.com',
    'CAD Import VCL demo', MB_OK);
    {$ENDIF}
    {$IFDEF FRDEMO}
    Application.MessageBox('Fast Report plugin demo - please register at www.cadsofttools.com',
    'Fast Report plugin demo', MB_OK);
    {$ENDIF}
  *)
  FAllArcsAsCurves := True;
  FImportMode := imView;
  FRefs := 1;

  FMain := TsgDXFSection(NewNamedEntity(nil, TsgDXFSection, 'SECTIONS'));
  FMain.OnListNotify := MainNotify;

  FTablesSection := TsgDXFSection(NewNamedEntity(FMain,
    cnstSectionNames[csTables].ClassType, cnstSectionNames[csTables].Name));
  FTablesSection.OnListNotify := TablesNotify;

  FObjectsSection := TsgDXFSection(NewNamedEntity(FMain,
    cnstSectionNames[csObjects].ClassType, cnstSectionNames[csObjects].Name));
  FObjectsSection.OnListNotify := ObjectsNotify;

  FBlocksSection := TsgDXFSection(NewNamedEntity(FMain,
    cnstSectionNames[csBlocks].ClassType, cnstSectionNames[csBlocks].Name));
  // FBlockRecords := TsgDXFSection(NewNamedEntity(FTablesSection, cnstSectionNames[csBlockRecords].ClassType,
  // cnstSectionNames[csBlockRecords].Name));
  FMStyles := TsgDXFTable(NewNamedEntity(FObjectsSection,
    cnstSectionNames[csMLineStyles].ClassType,
    cnstSectionNames[csMLineStyles].Name));
  FLayouts := TsgDXFTable(NewNamedEntity(FObjectsSection,
    cnstSectionNames[csLayouts].ClassType, cnstSectionNames[csLayouts].Name));
  FLayouts.OnListNotify := LayoutsNotify;

  FImageDefs := TsgDXFTable(NewNamedEntity(FObjectsSection,
    cnstSectionNames[csImageDefs].ClassType,
    cnstSectionNames[csImageDefs].Name));

  FXRefs := TList.Create;
  FCanvas := TCanvas.Create;
  // FContainerXref := nil;
  FNumberOfPartsInSpline := GetNumberOfSplineParts;
  FNumberOfPartsInCircle := GetNumberOfCircleParts;
  FDefaultLayoutIndex := -1;
  FTransform3D := cnstIdentityMat;

  AddLayout(TsgDXFLayout.Create);
  vLayout := TsgDXFLayout.Create;
  vLayout.Name := sLayout + '1';
  AddLayout(vLayout);

  FViewPortRect := BadRect;
  FViewTwistMatrix := cnstIdentityMat;
  vFonstPaths := '';
  if bSearchSHXPaths then
  begin
    vPaths := TStringList.Create;
    try
      FindAutoCADSHXPaths(vPaths);
      for I := 0 to vPaths.Count - 1 do
        vFonstPaths := vFonstPaths + vPaths[I] + ';';
    finally
      vPaths.Free;
    end;
  end;
  vFonstPaths := vFonstPaths + sSHXSearchPaths;
  while AnsiPos(';;', vFonstPaths) > 0 do
    Delete(vFonstPaths, AnsiPos(';;', vFonstPaths), 1);
  if vFonstPaths <> '' then
  begin
    if vFonstPaths[1] = ';' then
      Delete(vFonstPaths, 1, 1);
    if vFonstPaths[Length(vFonstPaths)] <> ';' then
      vFonstPaths := vFonstPaths + ';'
  end;
  FSHXFonts := TsgSHXFontList.Create(vFonstPaths, sDefaultSHXFont);
  FUseSHXFonts := bUseSHXFonts;
  FIsCrossoverMatrix := True;
  FMeshQuality := cnstDeviationCoefficientDefault;
  Initialize;
  HeadVarStructInit;
  FEntityDictionary := TsgCollection.Create;
  FEntityDictionary.Sorted := True;
  FEntityDictionary.Duplicates := dupIgnore;
end;

constructor TsgDXFConverter.CreateFromFile(const AFileName: string);
begin
  Create;
  FileName := AFileName;
end;

function TsgDXFConverter.CreateTextStyles(const AppLanguage: TsgLangugeID;
  const ACreate: Boolean): TsgDXFStyle;
var
  I: Integer;
  vStyle: TsgDXFStyle;
  vHeadVarStruct: PsgHeadVarStruct;
begin
  vHeadVarStruct := PHeadVarStruct;
  if ACreate then
  begin
    vHeadVarStruct^.TextStyle := cnstActiveStyles[AppLanguage];
    vHeadVarStruct^.DimTextStyle := vHeadVarStruct^.TextStyle;
    Result := StyleByName(vHeadVarStruct^.TextStyle);
    for I := Low(cnstCadStyles) to High(cnstCadStyles) do
    begin
      if (cnstCadStyles[I].LangIds = []) or
        (AppLanguage in cnstCadStyles[I].LangIds) then
      begin
        vStyle := StyleByName(cnstCadStyles[I].Name);
        vStyle.FontName := cnstCadStyles[I].Font;
        vStyle.PrimaryFont := cnstCadStyles[I].FFile;
        if vStyle.Name = cnstGost then
          vStyle.ObliqueAngle := 15;
        vStyle.Loaded(Self);
      end;
    end;
  end
  else
    Result := StyleByName(vHeadVarStruct^.TextStyle);
end;

function TsgDXFConverter.CustomEntByName(const AName: string;
  const ASection: TConvSection): TsgDXFEntity;
const
  cnstTableItemClasses: array [TConvSection] of TsgDXFEntityClass =
    (TsgDXFTable, TsgDXFBlock, TsgDXFEntity, TsgDXFLineType, TsgDXFLayer,
    TsgDXFStyle, TsgDXFDimensionStyle, TsgDXFBlockRecord, TsgDXFVport,
    TsgMLineStyle, TsgDXFImageDef, TsgDXFLayout, TsgDXFAcadTableStyle,
    TsgDXFDictionary);
var
  vSection: TsgDXFTable;
  vName: string;
begin
  vSection := TsgDXFTable(Sections[ASection]);
  vName := cnstSectionNames[ASection].Name;
  if not Assigned(vSection) then
  begin
    case ASection of
      csBlockRecords:
        vSection := TsgDXFTable(NewNamedEntity(Sections[csTables],
          cnstSectionNames[ASection].ClassType, vName));
      csTableStyles, csImageDefs, csMLineStyles, csLayouts:
        vSection := TsgDXFTable(NewNamedEntity(Sections[csObjects],
          cnstSectionNames[ASection].ClassType, vName));
    else
      if ASection = csEntities then
        vName := '';
      vSection := NewNamedTable(vName, cnstSectionNames[ASection].ClassType);
    end;
    Loads(vSection);
    Sections[ASection] := vSection;
  end;
  Result := vSection.FindEntByName(AName);
  if not Assigned(Result) then
  begin
    Result := NewNamedEntity(vSection, cnstTableItemClasses[ASection], AName);
    Loads(Result);
  end;
end;

destructor TsgDXFConverter.Destroy;
begin
  DestroyXDataProcs;
  FreeAndNil(FConvExtended);
  ClearBegin;
  Clear;
  FStatus := stDestroying;
  FreeSource;
  FCanvas.Free;

  FTablesSection.Free;
  FObjectsSection.Free;
  FBlocksSection.Free;
  FHeaderSection.Free;
  FEntitiesSection.Free;

  FXRefs.Free;

  DeletePaperLayout;
  DeleteModelLayout;
  FLayouts.Free;

  FMain.Free;
  FSHXFonts.Free;
  FreeAndNil(FXRefSearchPaths);
  ClearEnd;
  FreeAndNil(FMapEntities);
{$IFDEF CONV_REFCOUNT}
  if FRefCount > 0 then
    // if FRefEnts.Count > 0 then;
    raise Exception.CreateFmt('Converter (FRefcount=%d) > 0', [FRefCount]);
  FRefEnts.Free;
{$ENDIF}
  FEntityDictionary.Free;
  inherited Destroy;
end;

procedure TsgDXFConverter.DestroyXDataProcs;
begin
{$IFDEF SG_BTI}
  FreeAndNil(FXDataProcs);
{$ENDIF}
end;

procedure TsgDXFConverter.Clear;
var
  I: Integer;
  vLayout: TsgDXFLayout;
  vStatus: TConvStatus;
  vObj: TsgDXFEntity;

  function RemoveSection(const ASection: TsgDXFSection): TsgDXFSection;
  begin
    ASection.Clear;
    Result := ASection;
    FMain.RemoveEntity(ASection);
  end;

begin
  vStatus := FStatus;
  try
    try
      for I := 0 to FEntityDictionary.Count - 1 do
      begin
        TsgTableItem(FEntityDictionary.List^[I].Data).Item := nil;
        FreeAndNil(TsgTableItem(FEntityDictionary.List^[I].Data));
      end;
      FEntityDictionary.Clear;
      Status := stClearing;
      FCount := 0;

      // clear xref blocks
      for I := FXRefs.Count - 1 downto 0 do
      begin
        vObj := FXRefs[I];
        vObj.Owner.RemoveEntity(vObj); // vObj removes from FXRefs list
        vObj.Free;
      end;

      if Assigned(FLayouts) then
      begin
        vObj := FLayouts;
        FObjectsSection.RemoveEntity(FLayouts);
        FLayouts := TsgDXFTable(vObj);
        for I := FLayouts.Count - 1 downto 0 do
        begin
          vLayout := Layouts[I];
          vLayout.PaperSpaceBlock := nil;
          if I >= 2 then
          begin
            FLayouts.DeleteEntity(I);
            vLayout.Free;
          end;
        end;
      end;

      FBlocksSection := RemoveSection(FBlocksSection);
      FObjectsSection := RemoveSection(FObjectsSection);
      FTablesSection := RemoveSection(FTablesSection);

      FMain.Clear;
      Status := stDefault;
    except
    end;
  finally
    if vStatus = stLoading then
      Status := stLoading;
  end;
end;

procedure TsgDXFConverter.ClearBegin;
begin
end;

procedure TsgDXFConverter.ClearBlocks;
var
  I, J, vCountBlockFinded: Integer;
  vIsBlockOfLayout: Boolean;
  vBlock: TsgDXFBlock;
  vStatus: TConvStatus;
begin
  vStatus := FStatus;
  try
    Status := stClearing;
    FCount := 0;
    I := 0;
    if FBlocksSection.FSortEntList <> nil then
      FBlocksSection.FSortEntList.Clear;
    vCountBlockFinded := 0;
    while I < FBlocksSection.Count do
    begin
      vBlock := TsgDXFBlock(FBlocksSection[I]);
      vIsBlockOfLayout := False;
      if (FLayouts <> nil) and (vCountBlockFinded < FLayouts.Count) then
        for J := 0 to FLayouts.Count - 1 do
          if TsgDXFLayout(FLayouts.Entities[J]).PaperSpaceBlock = vBlock then
          begin
            vIsBlockOfLayout := True;
            Inc(vCountBlockFinded);
            Break;
          end;
      if vIsBlockOfLayout then
      begin
        vBlock.Clear(True);
        if FBlocksSection.FSortEntList <> nil then
          FBlocksSection.FSortEntList.AddObject(vBlock.EntName, vBlock);
        Inc(I);
      end
      else
      begin
        FBlocksSection.DeleteEntity(I);
        vBlock.Free;
      end;
    end;
  finally
    Status := vStatus;
  end;
end;

procedure TsgDXFConverter.ClearEnd;
begin
end;

class function TsgDXFConverter.CompareEntities(const AEnt1,
  AEnt2: Pointer): Integer;
begin
  Result := CompareHandleEntities(AEnt1, AEnt2);
end;

function TsgDXFConverter.Count: Integer;
begin
  if not(FStatus = stLoading) then
    Result := FCount
  else
    Result := FSource.Size;
  if Result = 0 then
    Result := 1;
end;

procedure TsgDXFConverter.GetLayerNames(S: TStrings;
  DoClear, IncludeUnused: Boolean);
var
  I: Integer;
  L: TsgDXFLayer;
begin
  S.BeginUpdate;
  try
    if DoClear then
      S.Clear;
    for I := 0 to Counts[csLayers] - 1 do
    begin
      L := Layers[I];
      if IncludeUnused or L.Used then
        S.AddObject(L.Name, L);
    end;
  finally
    S.EndUpdate;
  end;
end;

function TsgDXFConverter.IntToColor(Value: Integer): TColor;
begin
  Result := sgFunction.IntToColor(Value);
end;

procedure TsgDXFConverter.Iterate(Proc, FinishProc: TsgCADEntityProc;
  var Params: TsgCADIterate);
begin
  FParams := @Params;
  Params.Insert := nil;
  Params.ConvertMatrixCurrentIndertToWCS := cnstIdentityMat;
  Params.Color := clByLayer;
  Params.XScale := 0.0;
  Params.YScale := 0.0;
  FEntities.Iterate(Self, Proc, FinishProc);
end;

function TsgDXFConverter.IterateEntitiesInBlocks(const AProc
  : TsgCADLoadEntitiy): Boolean;
var
  vBlock: TsgDXFBlock;
  vBlocks: TsgDXFGroup;
  I, J: Integer;
begin
  Result := False;
  vBlocks := Sections[csBlocks];
  if Assigned(vBlocks) then
  begin
    for I := 0 to vBlocks.Count - 1 do
    begin
      vBlock := TsgDXFBlock(vBlocks.Entities[I]);
      for J := 0 to vBlock.Count - 1 do
      begin
        if not Assigned(vBlock.Layout) then
          if AProc(vBlock.Entities[J], Self) then
            Result := True;
      end;
    end;
    for I := 0 to LayoutsCount - 1 do
    begin
      vBlock := Layouts[I].PaperSpaceBlock;
      for J := 0 to vBlock.Count - 1 do
      begin
        if AProc(vBlock.Entities[J], Self) then
          Result := True;
      end;
    end;
  end;
end;

function TsgDXFConverter.LayerByName(const AName: string): TsgDXFLayer;
begin
  Result := TsgDXFLayer(CustomEntByName(AName, csLayers));
end;

function TsgDXFConverter.LinesByName(const AName: string): TsgLines;
var
  L: TsgDXFLineType;
begin
  L := LTypeByName(AName);
  if L = nil then
    Result := nil
  else
    Result := L.FLines;
end;

function TsgDXFConverter.FEntities: TsgDXFBlock;
begin
  Result := Layouts[0].PaperSpaceBlock;
end;

procedure TsgDXFConverter.FreeEntitiesWithGeneratedHandles;
begin
  if FMapEntities.HasGeneratedList then
    FMapEntities.ApplyAndFreeGeneratedList;
end;

procedure TsgDXFConverter.FreeSource;
begin
  if OwnSource then
    FSource.Free;
  FSource := nil;
end;

function TsgDXFConverter.FromXML(const ANode: TsgNodeSample;
  const AResult: IsgResultNode = nil): Integer;

  function IsNodeEntity(const ANode: TsgNodeSample): Boolean;
  var
    vSubEntities: TList;
    vNameNode: TsgNodeSample;
    I: Integer;
  begin
    Result := False;
    vSubEntities := TList.Create;
    try
      GetSubEntities(vSubEntities);
      vNameNode := ANode.GetAttributeByName
        (sgConsts.cnstXMLNames[xmlName].Name);
      if not Assigned(vNameNode) then
        Exit;
      for I := 0 to vSubEntities.Count - 1 do
      begin
        if SameText(TsgDXFEntity(vSubEntities[I]).Name, vNameNode.ValueAsStr)
        then
        begin
          Result := True;
          Break;
        end;
      end
    finally
      vSubEntities.Free;
    end;
  end;

var
  vActive, vNodeChild, vNodeEntities, vNodeModel, vSubEntity: TsgNodeSample;
  vEntitiesName: string;
  vEntitiesNodeCreate: Boolean;
begin
  vActive := ANode;
  if not SameText(GetNodeName, ANode.Name) then
  begin
    vSubEntity := nil;
    vActive := TsgNode(ANode).AddChildNV(GetNodeName);
    if not Assigned(FEntitiesSection) then
      FEntitiesSection := TsgDXFSectionEntities.CreateByConverter(Self);
    vEntitiesName := FEntitiesSection.GetNodeName;
    vNodeEntities := vActive.GetChildByName(vEntitiesName);
    vEntitiesNodeCreate := False;
    if not Assigned(vNodeEntities) then
    begin
      // cstSectionEntities
      vNodeEntities := TsgNode.Create;
      vEntitiesNodeCreate := True;
      vNodeEntities.Name := vEntitiesName;
      TsgNode(vNodeEntities).AddAttribNV(cnstXMLNames[xmlName].Name).ValueAsStr
        := FEntitiesSection.Name;
      // Model
      vNodeModel := TsgNode(vNodeEntities)
        .AddChildNV(Sections[csEntities].GetNodeName);
      TsgNode(vNodeModel).AddAttribNV(cnstXMLNames[xmlName].Name).ValueAsStr :=
        Sections[csEntities].Name;
      vSubEntity := TsgNode(vNodeModel)
        .AddChildNV(cnstXMLNames[xmlSubEntities].Name);
    end
    else
    begin
      if vNodeEntities.ChildNodesCount = 1 then
      begin
        vSubEntity := vNodeEntities.ChildNodes[0].GetChildByName
          (cnstXMLNames[xmlSubEntities].Name);
      end;
    end;
    while ANode.ChildNodesCount > 1 do
    begin
      vNodeChild := ANode.ChildNodes[0];
      if (vActive <> vNodeChild) then
      begin
        TsgNode(ANode).RemoveChild(vNodeChild);
        if (not IsNodeEntity(vNodeChild)) and Assigned(vSubEntity) then
          TsgNode(vSubEntity).AddChild(vNodeChild)
        else
          TsgNode(vActive).AddChild(vNodeChild);
      end;
    end;
    if vEntitiesNodeCreate then
      TsgNode(vActive).AddChild(vNodeEntities);
  end;
  Result := inherited FromXML(vActive, AResult);
end;

function TsgDXFConverter.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  vEntity: TsgDXFEntity;
  vHandleNode, vNameNode: TsgNodeSample;
  vSubEntities: TList;
  I: Integer;
  vHandle: UInt64;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlClassId:
      begin
        vEntity := nil;
        vHandleNode := nil;
        vHandle := cnstBadHandle;
        vNameNode := ANode.GetAttributeByName
          (sgConsts.cnstXMLNames[xmlName].Name);
        if not Assigned(vNameNode) then
        begin
          vHandleNode := ANode.GetAttributeByName
            (sgConsts.cnstXMLNames[xmlHandle].Name);
          if Assigned(vHandleNode) then
          begin
            vHandle := RestoreHandle(vHandleNode);
            if vHandle = cnstBadHandle then
              vHandleNode := nil;
          end;
        end;
        if Assigned(vNameNode) or Assigned(vHandleNode) then
        begin
          vSubEntities := TList.Create;
          try
            GetSubEntities(vSubEntities);
            for I := 0 to vSubEntities.Count - 1 do
            begin
              if Assigned(vNameNode) then
              begin
                if SameText(TsgDXFEntity(vSubEntities[I]).Name,
                  vNameNode.ValueAsStr) then
                begin
                  vEntity := TsgDXFEntity(vSubEntities[I]);
                  Break;
                end;
              end
              else
              begin
                if TsgDXFEntity(vSubEntities[I]).Handle = vHandle then
                begin
                  vEntity := TsgDXFEntity(vSubEntities[I]);
                  Break;
                end;
              end;
            end;
          finally
            vSubEntities.Free;
          end;
        end;
        if Assigned(vEntity) then
        begin
          vEntity.SetConverter(Self);
          vEntity.FromXML(ANode, AResult);
        end
        else
        begin
          raise Exception.Create('Error section!');
        end;
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFConverter.FromXMLSubEntities(const ANode: TsgNodeSample;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLSubEntities(ANode, AResult);
end;

procedure TsgDXFConverter.SaveHandle(const AValue: string;
  const AEntity: TsgDXFEntity);
begin
  GetConvExtended.SaveHandle(AValue, AEntity);
end;

procedure TsgDXFConverter.SetActiveVPort(const AValue: TsgDXFVport);
begin
  FActiveVPort := AValue;
  if Assigned(FActiveVPort) then
    FViewTwistMatrix := GetViewTwistMatrix(ActiveVPort.ViewDirection,
      ActiveVPort.ViewTwistAngle)
  else
    FViewTwistMatrix := cnstIdentityMat;
  if not FIsCrossoverMatrix then
    FViewTwistMatrix := FMatXMat(FViewTwistMatrix, FMatByScales(1, -1, 1));
end;

procedure TsgDXFConverter.SetAngle(const AAngle: Single);
var
  vValue: Double;
begin
  if sgModAngle(AAngle, vValue) then
    ActiveVPort.ViewTwistAngle := vValue;
end;

procedure TsgDXFConverter.SetCircleZoomPercent(const AVal: Integer);
begin
  ActiveVPort.CircleZoomPercent := AVal;
end;

procedure TsgDXFConverter.SetSource(Value: TCustomMemoryStream);
begin
  if Value <> FSource then
  begin
    FreeSource;
    FSource := Value;
  end;
end;

procedure TsgDXFConverter.SetOwnSource(Value: Boolean);
begin
  if Value <> FOwnSource then
  begin
    FreeSource;
    FOwnSource := Value;
  end;
end;

class procedure TsgDXFConverter.SetLayerNameOfPassingInspection
  (const ALayer: TsgDXFLayer; const AName: string);
begin
  ALayer.SetNameDirect(AName);
end;

procedure TsgDXFConverter.SetLoading(Value: Boolean; APos: PAnsiChar);
begin
  if Value then
  begin
    if (Status <> stLoading) and FMapEntities.HasGeneratedList then
      ResetHandles;
    Status := stLoading
  end
  else
  begin
    Status := stDefault;
    InitializeSectionsEnd;
  end;
  FPos := APos;
  if FPos <> nil then
    Inc(FPos);
end;

type
  TMemoryStreamAccess = class(TMemoryStream);

procedure TsgDXFConverter.SetSourceStream(S: TStream);
var
  MS: TMemoryStream;
  vSize: Int64;
begin
  // MS := TMemoryStream(S);//evg
  MS := TMemoryStream.Create; // evg???? create without free!
  vSize := S.Size - S.Position;
  TMemoryStreamAccess(MS).Capacity := vSize + 4;
  MS.Size := vSize;
  S.ReadBuffer(MS.Memory^, vSize);
  // MS.LoadFromStream(S);
  OwnSource := True;
  Source := MS;
  FLimit := MS.Memory;
  if Assigned(FLimit) then
  begin
    Inc(FLimit, vSize);
    PWord(FLimit)^ := $0A0D; // additional eoln for DXF.SkeepLimits
    PWord(TsgNativeUInt(FLimit) + 2)^ := $0000;
  end;
end;

procedure TsgDXFConverter.SetStatus(const AValue: TConvStatus);
begin
  FStatus := AValue;
end;

procedure TsgDXFConverter.SetVPort(const APt: TFPoint);
begin
  ActiveVPort.ViewDirection := APt;
end;

procedure TsgDXFConverter.SetXRefSearchPath(const Value: string);
begin
  XRefSearchPaths.Text := Value;
end;

procedure TsgDXFConverter.Load;
begin
end;

procedure TsgDXFConverter.DoCreate(Sender: TObject);
begin
  if Assigned(FOnCreate) then
    FOnCreate(Sender);
end;

procedure TsgDXFConverter.DoExtents;
var
  I: Integer;
begin
  for I := 0 to LayoutsCount - 1 do
    Layouts[I].Loaded(Self);
  // corrects Handle value (DoExtents in previous versions)
end;

function TsgDXFConverter.DoFindFont(const AEntity: TsgDXFEntity;
  const ABigFont: Boolean; const AFontName: string): string;
begin
  if ABigFont then
    Result := 'Arial Unicode MS'
  else
    Result := cnstDefaultTTFFont;
  if Assigned(FOnFindFont) then
    FOnFindFont(AEntity, Self, ABigFont, AFontName, Result);
end;

procedure TsgDXFConverter.EntityListNotify(Ptr: Pointer;
  Action: TListNotification);
begin
  case Action of
    lnAdded:
      begin
        FMapEntities.UnActivateRegister;
      end;
    lnDeleted, lnExtracted:
      begin
        FMapEntities.UnActivateRegister; // ??
        TsgDXFEntity(Ptr).Dictionary := nil;
      end;
  end
end;

function TsgDXFConverter.ExtractFromTable(const ATable: TsgDXFGroup;
  const AEntity: TsgDXFEntity): TsgDXFEntity;
begin
  Result := nil;
  if (ATable <> nil) and (ATable.Count > 0) then
  begin
    if ATable.RemoveEntity(AEntity) then
      Result := AEntity;
  end;
end;

procedure TsgDXFConverter.Loads(E: TsgDXFEntity);
begin
  E.Loaded(Self);
  Inc(FCount);
end;

procedure TsgDXFConverter.LoadsGroup(E: TsgDXFEntity);
var
  I: Integer;
begin
  SetHandleGroup(E);
  for I := 0 to E.Count - 1 do
    E.Entities[I].LoadedInternal(Self);
  Inc(FCount, E.Count);
end;

procedure TsgDXFConverter.LoadsByClasses(const AEntityClasses
  : array of TsgDXFEntityClass);
var
  I, J, K, C: Integer;
  vEntity: TsgDXFEntity;
  vEntities: TsgDXFEntity;
begin
  for K := Low(AEntityClasses) to High(AEntityClasses) do
    for I := 0 to FBlocksSection.Count - 1 do
    begin
      vEntities := FBlocksSection[I];
      C := vEntities.Count;
      Dec(C);
      for J := 0 to C do
      begin
        vEntity := vEntities[J];
        if Assigned(vEntity) then
        begin
          if vEntity.InheritsFrom(AEntityClasses[K]) then
            vEntity.Loaded(Self)
          else if (vEntity.InheritsFrom(TsgDXFXref)) and
            (TsgDXFXref(vEntity).CADImage is TsgCADImage) and
            (TsgCADImage(TsgDXFXref(vEntity).CADImage).Converter <> nil) then
            TsgCADImage(TsgDXFXref(vEntity).CADImage).Converter.LoadsByClasses
              (AEntityClasses);
        end;
      end;
    end;
end;

function TsgDXFConverter.LTypeByName(const AName: string): TsgDXFLineType;
begin
  Result := nil;
  if FLTypes = nil then
    Exit;
  Result := TsgDXFLineType(FLTypes.FindEntByName(AName));
end;

procedure TsgDXFConverter.MainNotify(Ptr: Pointer; Action: TListNotification);
var
  vName: string;
begin
  case Action of
    lnExtracted, lnDeleted:
      begin
        if Ptr = FBlocksSection then
          Sections[csBlocks] := nil
        else if Ptr = FTablesSection then
          Sections[csTables] := nil
        else if Ptr = FObjectsSection then
        begin
          TsgDXFSection(Ptr).OnListNotify := nil;
          Sections[csObjects] := nil;
        end;
      end;
    lnAdded:
      begin
        vName := TsgDXFEntity(Ptr).Name;
        if vName = cnstSectionBLOCKS then
          Sections[csBlocks] := TsgDXFSection(Ptr)
        else if vName = cnstSectionTABLES then
          Sections[csTables] := TsgDXFSection(Ptr)
        else if vName = cnstSectionOBJECTS then
        begin
          Sections[csObjects] := TsgDXFSection(Ptr);
          TsgDXFSection(Ptr).OnListNotify := ObjectsNotify;
        end;
      end;
  end;
end;

procedure TsgDXFConverter.ObjectsNotify(Ptr: Pointer;
  Action: TListNotification);
var
  vName: string;
  I: Integer;
  Ent: TsgDXFEntity absolute Ptr;
begin
  case Action of
    lnDeleted, lnExtracted:
      begin
        if Ptr = FImageDefs then
          FImageDefs := nil
        else if Ptr = FMStyles then
          FMStyles := nil
        else if Ptr = FTableStyles then
          FTableStyles := nil
        else if Ptr = FLayouts then
          FLayouts := nil
        else if Ptr = FFieldList then
          FFieldList := nil
        else if Ptr = FSortEntsTables then
          FSortEntsTables := nil
        else if (Ent is TsgDXFDictionary) and Assigned(FLayers) then
          for I := 0 to FLayers.Count - 1 do
            if TsgDXFPenTableItem(FLayers[I]).Dictionary = Ent then
              TsgDXFPenTableItem(FLayers[I]).Dictionary := nil;
      end;
    lnAdded:
      begin
        vName := TsgDXFEntity(Ptr).Name;
        if (vName = cnstObjectsLAYOUTS) or (vName = sAcadLayoutDictionary) then
        begin
          FLayouts := TsgDXFTable(Ptr);
          FLayouts.OnListNotify := LayoutsNotify;
          // FLayouts.InternalFlags := FLayouts.InternalFlags or 2;
        end
        else if (vName = cnstObjectsIMAGEDEFS) or (vName = sAcadImageDict) then
          FImageDefs := TsgDXFTable(Ptr)
        else if (vName = cnstObjectsMLINESTYLES) or
          (vName = sAcadMLineStyleDictionary) then
          FMStyles := TsgDXFTable(Ptr)
        else if (vName = cnstObjectsTABLESTYLES) or
          (vName = sAcadTableStyleDictionary) then
          FTableStyles := TsgDXFTable(Ptr)
        else if (vName = cnstObjectsFIELDLIST) or
          (vName = sAcadFieldListDictionary) then
          FFieldList := TsgDXFFieldList(Ptr)
        else if (vName = sDictionaryVarSORTENTS) then
          FSortEntsTables := TsgDXFTable(Ptr);
      end;
  end;
end;

procedure TsgDXFConverter.TablesNotify(Ptr: Pointer; Action: TListNotification);
var
  vName: string;
begin
  case Action of
    lnDeleted, lnExtracted:
      begin
        if Ptr = FBlockRecords then
          FBlockRecords := nil
        else if Ptr = FLTypes then
        begin
          // FLTypes.InternalFlags := FLTypes.InternalFlags and not 2;
          FLTypes := nil;
        end
        else if Ptr = FLayers then
        begin
          // FLayers.InternalFlags := FLayers.InternalFlags and not 2;
          FLayers := nil;
        end
        else if Ptr = FStyles then
          FStyles := nil
        else if Ptr = FDimStyles then
          FDimStyles := nil
        else if Ptr = FVPorts then
          FVPorts := nil;
      end;
    lnAdded:
      begin
        vName := TsgDXFEntity(Ptr).Name;
        if vName = cnstTableBLOCK_RECORD then
          FBlockRecords := TsgDXFTable(Ptr)
        else if vName = cnstTableLTYPE then
        begin
          FLTypes := TsgDXFTable(Ptr);
          FLTypes.InternalFlags := FLTypes.InternalFlags or 2;
        end
        else if vName = cnstTableLAYER then
        begin
          FLayers := TsgDXFTable(Ptr);
          FLayers.InternalFlags := FLayers.InternalFlags or 2;
        end
        else if vName = cnstTableSTYLE then
        begin
          FStyles := TsgDXFTable(Ptr);
          FStyles.InternalFlags := FStyles.InternalFlags or 2;
        end
        else if vName = cnstTableDIMSTYLE then
        begin
          FDimStyles := TsgDXFTable(Ptr);
          FDimStyles.InternalFlags := FDimStyles.InternalFlags or 2;
        end
        else if vName = cnstTableVPORT then
          FVPorts := TsgDXFTable(Ptr);
      end;
  end;
end;

{ function TsgDXFConverter.BlockRecordByName(const AName: string): TsgDXFBlockRecord;
  begin
  Result := TsgDXFBlockRecord(CustomEntByName(AName, csBlockRecords));
  end; }

function TsgDXFConverter.BlockRecordByHandle(const AHandle: UInt64)
  : TsgDXFBlockRecord;
begin
  if Counts[csBlockRecords] > 0 then
    Result := TsgDXFBlockRecord(Sections[csBlockRecords]
      .FindEntByHandle(AHandle))
  else
    Result := nil;
end;

function TsgDXFConverter.BlockRecordNameByHandle(const AHandle: UInt64): string;
var
  vBlockRecord: TsgDXFBlockRecord;
begin
  Result := '';
  vBlockRecord := BlockRecordByHandle(AHandle);
  if Assigned(vBlockRecord) then
    Result := vBlockRecord.Name;
end;

function TsgDXFConverter.LayoutByName(AName: string): TsgDXFLayout;
begin
  if Assigned(FLayouts) then
    Result := TsgDXFLayout(FLayouts.FindEntByName(AName))
  else
    Result := nil;
end;

procedure TsgDXFConverter.LayoutsNotify(Ptr: Pointer;
  Action: TListNotification);
begin
  case Action of
    lnAdded:
      if Assigned(FOnLayoutAdd) then
        FOnLayoutAdd(Ptr);
    lnDeleted, lnExtracted:
      if Assigned(FOnLayoutRemove) then
        FOnLayoutRemove(Ptr);
  end;
end;

function TsgDXFConverter.GetMainConverter: TsgDXFConverter;
begin
  Result := Self;
  while Result.FOwnerConverter <> nil do
    Result := Result.FOwnerConverter;
end;

function TsgDXFConverter.GetModelLayout: TsgDXFLayout;
begin
  // Model is Layout with zero-index
  Result := TsgDXFLayout(FLayouts.Entities[0]);
end;

function TsgDXFConverter.GetModelMatrix: TFMatrix;
begin
  Result := GetModelLayout.RotMatrix;
end;

function TsgDXFConverter.NewEntity(AOwner: TsgDXFEntity;
  AClass: TsgDXFEntityClass): TsgDXFEntity;
begin
  Result := NewNamedEntity(AOwner, AClass, '');
end;

function TsgDXFConverter.NewNamedEntity(AOwner: TsgDXFEntity;
  AClass: TsgDXFEntityClass; const AName: string): TsgDXFEntity;
begin
  Result := nil;
  if Assigned(AOwner) then
    Result := AOwner.FindEntByName(AName);
  if not Assigned(Result) then
  begin
    Result := AClass.Create;
    DoCreate(Result);
    Result.SetConverter(Self);
    Result.SetName(AName);
    if Assigned(AOwner) and (AOwner.AddEntity(Result) < 0) then
      FreeAndNil(Result);
  end;
end;

function TsgDXFConverter.NewNamedTable(const AName: string;
  AClassType: TsgDXFEntityClass): TsgDXFTable;
var
  vTableClass: TsgDXFEntityClass;
begin
  vTableClass := AClassType;
  if vTableClass = nil then
    vTableClass := TsgDXFTable;
  Result := TsgDXFTable(NewNamedEntity(Sections[csTables], vTableClass, AName));
  Loads(Result); // to set handle
end;

function TsgDXFConverter.NewTable(const AType: TConvSection): TsgDXFTable;
begin
  Result := NewNamedTable(cnstSectionNames[AType].Name,
    cnstSectionNames[AType].ClassType);
end;

function TsgDXFConverter.Pos: Integer;
begin
  if FSource = nil then
    Result := 0
  else
    Result := FPos - FSource.Memory;
end;

function TsgDXFConverter.GetExtents: TFRect;
begin
  FExtents.TopLeft := HeadVarStruct.ExtMim;
  FExtents.BottomRight := HeadVarStruct.ExtMax;
  Result := FExtents;
end;

function TsgDXFConverter.GetFieldList: TsgDXFFieldList;
begin
  if not Assigned(FFieldList) then
  begin
    FFieldList := TsgDXFFieldList(Sections[csObjects].FindEntByName
      (cnstObjectsFIELDLIST));
    if not Assigned(FFieldList) then
      FFieldList := TsgDXFFieldList(NewNamedEntity(Sections[csObjects],
        TsgDXFFieldList, cnstObjectsFIELDLIST));
  end;
  Result := FFieldList;
end;

procedure TsgDXFConverter.Reference;
begin
  Inc(FRefs);
end;

class procedure TsgDXFConverter.RegisterXRefGraphicClass(AExt: string;
  AGraphicClass: TGraphicClass);
begin
  if (Length(AExt) > 0) and (AExt[1] <> '.') then
    AExt := '.' + AExt;
  XRefFileClasses.AddObject(AExt, TObject(AGraphicClass));
end;

function TsgDXFConverter.ReInitBlockByEntities(const AInserts: TList): Boolean;
var
  I: Integer;
begin
  if Assigned(AInserts) then
  begin
    Result := False;
    for I := 0 to AInserts.Count - 1 do
      if SetBlockByInsert(AInserts.List[I], Self) then
        Result := True;
  end
  else
    Result := IterateEntitiesInBlocks(@SetBlockByInsert);
end;

procedure TsgDXFConverter.Release;
begin
  if FRefs > 0 then
    Dec(FRefs);
  if FRefs > 0 then
    Exit;
  if FStatus = stLoading then
  begin
    StopLoading;
    Status := stDefault;
  end
  else
    Destroy;
end;

{ function TsgDXFConverter.SortEntities: Boolean;
  var
  vSortBlocks: TsgList;
  J, CntJ: Integer;
  vSortEntTable: TsgDXFSortEntsTable;
  begin
  vSortBlocks := TsgList.Create;
  try
  vSortBlocks.Sorted := True;
  for J := 0 to LayoutsCount - 1 do
  vSortBlocks.Add(Layouts[J].PaperSpaceBlock);
  if (FSortEntsTables <> nil) and (FSortEntsTables.Count > 0) then
  begin
  CntJ := FSortEntsTables.Count - 1;
  for J := 0 to CntJ do
  begin
  vSortEntTable := TsgDXFSortEntsTable(FSortEntsTables[J]);
  SortEntitiesByHandle(vSortEntTable, vSortEntTable.SortObject);
  vSortBlocks.Remove(vSortEntTable.SortObject);
  end;
  end;
  for J := 0 to vSortBlocks.Count - 1 do
  TsgDXFGroup(vSortBlocks[J]).SortEntByHandle;
  //Result := SortEntitiesInZDepth;
  Result := True;
  finally
  vSortBlocks.Free;
  end;
  end; }
procedure TsgDXFConverter.SortEntities;
var
  J, CntJ: Integer;
  vBlock: TsgDXFEntity;
  vSortEntTable: TsgDXFSortEntsTable;
begin
  if (FSortEntsTables <> nil) and (FSortEntsTables.Count > 0) then
  begin
    CntJ := FSortEntsTables.Count - 1;
    for J := 0 to CntJ do
    begin
      vSortEntTable := TsgDXFSortEntsTable(FSortEntsTables[J]);
      vBlock := vSortEntTable.SortObject;
      if vBlock is TsgDXFBlockRecord then
        vBlock := TsgDXFBlockRecord(vBlock).Block;
      if Assigned(vBlock) then
        SortEntitiesByHandle(vSortEntTable, vBlock);
    end;
  end
  else
    SortEntitiesInZDepth;
end;

procedure TsgDXFConverter.SortEntitiesByHandle(const ATable,
  ABlock: TsgDXFEntity);
begin
  if (ATable <> nil) and (ABlock <> nil) then
    TsgDXFSortEntsTable(ATable).SortEntities(ABlock);
end;

function TsgDXFConverter.SortEntitiesInZDepth: Boolean;
var
  I, Cnt: Integer;
  vBox: TFRect;
  Z0: Double;
  vIsNeedSort: Boolean;
begin
  vIsNeedSort := False;
  if FEntities.Count > 1 then
  begin
    vIsNeedSort := False;
    vBox := FEntities[0].GetBox;
    Z0 := (vBox.Z1 + vBox.Z2) * 0.5;
    Cnt := FEntities.Count - 1;
    I := 0;
    while (not vIsNeedSort) and (I <= Cnt) do
    begin
      vBox := FEntities[I].GetBox;
      vIsNeedSort := vIsNeedSort or
        (Abs(Z0 - (vBox.Z1 + vBox.Z2) * 0.5) > fAccuracy);
      Inc(I);
    end;
    if vIsNeedSort then
      QSortList(FEntities.FEntities, CompareZDepthEntities);
  end;
  Result := vIsNeedSort;
end;

procedure TsgDXFConverter.StopLoading;
begin
  if FSource <> nil then
    FPos := FSource.Memory;
end;

function TsgDXFConverter.DimensionStyleByName(const AName: string)
  : TsgDXFDimensionStyle;
begin
  Result := TsgDXFDimensionStyle(CustomEntByName(AName, csDimStyles));
end;

function TsgDXFConverter.StyleByName(const AName: string): TsgDXFStyle;
var
  vName: string;
begin
  if AName = '' then
    vName := sStandardName
  else
    vName := UpperCase(AName);
  Result := TsgDXFStyle(CustomEntByName(vName, csStyles));
end;

function TsgDXFConverter.StyleByPrimaryFont(const AName: string): TsgDXFStyle;
var
  I: Integer;
begin
  Result := nil;
  if (Length(AName) > 0) and (FStyles <> nil) then
  begin
    for I := 0 to FStyles.Count - 1 do
    begin
      if TsgDXFStyle(FStyles.Entities[I]).GetPrimaryFontName = AName then
      begin
        Result := TsgDXFStyle(FStyles.Entities[I]);
        Break;
      end;
    end;
  end;
end;

function TsgDXFConverter.TableStyleByName(const AName: string)
  : TsgDXFAcadTableStyle;
begin
  Result := TsgDXFAcadTableStyle(CustomEntByName(AName, csTableStyles));
end;

class procedure TsgDXFConverter.UnRegisterXRefGraphicClass
  (AGraphicClass: TGraphicClass);
var
  I: Integer;
  C: TGraphicClass;
begin
  I := 0;
  while I < XRefFileClasses.Count do
  begin
    C := TGraphicClass(XRefFileClasses.Objects[I]);
    if C.InheritsFrom(AGraphicClass) then
      XRefFileClasses.Delete(I)
    else
      Inc(I);
  end;
end;

procedure TsgDXFConverter.Initialize;
begin
end;

procedure TsgDXFConverter.DeleteModelLayout;
begin
  if LayoutsCount > 0 then
    FLayouts.DeleteEntity(0).Free;
end;

procedure TsgDXFConverter.DeletePaperLayout;
begin
  if LayoutsCount > 1 then
    FLayouts.DeleteEntity(1).Free;
end;

// Generates a ViewPort for Model_Space
procedure TsgDXFConverter.GenerateDisplayAndModelViewPort
  (const ALayout: TsgDXFLayout; const AWidth, AHeight: Double;
  const AMode: Integer; const ABox: PFRect = nil);
var
  vRect: TFRect;
  vRatioKoef, vMWidth, vMHeight, vWidth, vHeight: Double;
  vViewPort: TsgDXFViewport;
  vPaperCenter: TFPoint;
begin
  vWidth := AWidth;
  vHeight := AHeight;
  if AMode > 0 then
  begin
    vRect := Layouts[0].Box;
    TransRectCorners(vRect, GetModelMatrix);
    vMWidth := vRect.Right - vRect.Left;
    if vMWidth <= fDoubleResolution then
      vMWidth := fDoubleResolution;
    vMHeight := vRect.Top - vRect.Bottom;
    vRatioKoef := vMHeight / vMWidth;
    vHeight := AWidth * vRatioKoef;
  end;
  vPaperCenter := MakeFPoint(vWidth * 0.5, vHeight * 0.5);
  vViewPort := GenerateDisplayViewPort(vWidth, vHeight);
  ALayout.AddEntity(vViewPort);
  vViewPort.PSpaceCenter := vPaperCenter;
  Loads(vViewPort);
  if cnstCreateViewportInNewLayouts then
  begin
    vViewPort := GenerateModelViewPort(vPaperCenter, vWidth, vHeight,
      ABox = nil, True);
    if ABox <> nil then
    begin
      vViewPort.MSpaceCenter := MiddleFPoint(ABox^.TopLeft, ABox^.BottomRight);
      vViewPort.MSpaceHeight := Abs(ABox^.Top - ABox^.Bottom);
      Loads(vViewPort);
    end;
    ALayout.AddEntity(vViewPort);
  end;
  Loads(ALayout);
end;

function TsgDXFConverter.GenerateDisplayViewPort(const AWidth, AHeight: Double)
  : TsgDXFViewport;
begin
  Result := TsgDXFViewport.Create;
  Result.PSpaceCenter := cnstFPointZero;
  Result.PSpaceWidth := AWidth;
  Result.PSpaceHeight := AHeight;
  Result.MSpaceCenter := Result.PSpaceCenter;
  Result.MSpaceHeight := Result.PSpaceHeight;
  Result.Flags := 32800; // ?special invisible Model flag
  Self.Loads(Result);
end;

function TsgDXFConverter.GenerateModelViewPort(const ACenter: TFPoint;
  const AWidth, AHeight: Double; const ALoad: Boolean;
  const AFitModel: Boolean = False): TsgDXFViewport;
var
  I: Integer;
  vRect: TFRect;
  vMWidth, vMHeight, vKWidth, vKHeight: Double;
begin
  vRect := GetModelLayout.Box;
  TransRectCorners(vRect, GetModelMatrix);
  Result := TsgDXFViewport.Create;
  // Add Layer by list - flag set is frozen by default in new viewports
  begin
    if Assigned(Result.FrozenLayers) then
      for I := 0 to Counts[csLayers] - 1 do
      begin
        if Layers[I].IsFrozenByNewViewPort then
          Result.FrozenLayers.Add(Layers[I].Handle);
      end;
  end;
  // Result.Flags := $8020;
  Result.Layer := Self.LayerByName(FHeadVarStruct.CLayer);
  Result.PSpaceCenter := ACenter;
  Result.PSpaceWidth := AWidth;
  Result.PSpaceHeight := AHeight;
  Result.MSpaceCenter := MiddleFPoint(vRect.TopLeft, vRect.BottomRight);
  vMHeight := vRect.Top - vRect.Bottom;
  if AFitModel and (AWidth > fDoubleResolution) and (AHeight > fDoubleResolution)
  then
  begin
    vMWidth := vRect.Right - vRect.Left;
    vKWidth := vMWidth / AWidth;
    vKHeight := vMHeight / AHeight;
    if vKHeight < vKWidth then
      vMHeight := AHeight * vKWidth;
  end;
  Result.MSpaceHeight := vMHeight;
  if Self.IsCrossoverMatrix then
  begin
    Result.ViewDirection := Self.VPort;
    Result.ViewTwistAngle := Self.Angle;
  end
  else
  begin
    Result.ViewDirection := MakeFPoint(0, 0, -1);
    Result.ViewTwistAngle := 180;
  end;
  Result.ThisID := 0;
  Result.StatusField := -1;
  Result.ViewTarget := cnstFPointZero;
  Result.VisibleBoundary := True;
  if ALoad then
    Self.Loads(Result);
end;

function TsgDXFConverter.GetActiveVPort: TsgDXFVport;
begin
  if FActiveVPort = nil then
    FActiveVPort := TsgDXFVport(CustomEntByName(sActiveVPort, csVPorts));
  Result := FActiveVPort;
end;

function TsgDXFConverter.GetAngle: Single;
begin
  Result := ActiveVPort.ViewTwistAngle;
end;

function TsgDXFConverter.GetBlock(Index: Integer): TsgDXFBlock;
begin
  Result := TsgDXFBlock(FBlocksSection[Index]);
end;

function TsgDXFConverter.GetCount(Index: TConvSection): Integer;
var
  vSection: TsgDXFGroup;
begin
  vSection := Sections[Index];
  if vSection <> nil then
    Result := vSection.Count
  else
    Result := 0;
end;

function TsgDXFConverter.GetEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := TsgDXFEntity(FEntities[AIndex]);
end;

function TsgDXFConverter.GetLayer(Index: Integer): TsgDXFLayer;
begin
  Result := TsgDXFLayer(FLayers[Index]);
end;

function TsgDXFConverter.GetLayout(const AIndex: Integer): TsgDXFLayout;
begin
  if (AIndex >= 0) and (AIndex < LayoutsCount) then
    Result := TsgDXFLayout(FLayouts.Entities[AIndex])
  else
    Result := nil;
end;

function TsgDXFConverter.GetLayoutsCount: Integer;
begin
  Result := Counts[csLayouts];
end;

function TsgDXFConverter.GetImageDef(const Index: Integer): TsgDXFImageDef;
begin
  Result := TsgDXFImageDef(FImageDefs.Entities[Index]);
end;

function TsgDXFConverter.GetStyle(Index: Integer): TsgDXFStyle;
begin
  Result := TsgDXFStyle(FStyles[Index]);
end;

procedure TsgDXFConverter.GetSubEntities(const AList: TList);
  procedure CheckAndCreateByConverter(var AValue: TsgDXFSection;
    AClassType: TsgDXFSectionForXMLExportClass);
  begin
    if AValue = nil then
      AValue := AClassType.CreateByConverter(Self);
  end;

begin
  if Assigned(AList) then
  begin
    AList.Add(GetHeaderSection);
    CheckAndCreateByConverter(FEntitiesSection, TsgDXFSectionEntities);
    AList.Add(FTablesSection);
    AList.Add(FBlocksSection);
    AList.Add(FEntitiesSection);
    AList.Add(FObjectsSection);
  end;
end;

function TsgDXFConverter.GetMainConverter(AMatrix: PFMatrix): TsgDXFConverter;
begin
  Result := Self;
  AMatrix^ := Result.FTransform3D;
  while Result.FOwnerConverter <> nil do
  begin
    Result := Result.FOwnerConverter;
    AMatrix^ := FMatXMat(Result.FTransform3D, AMatrix^);
  end;
end;

function TsgDXFConverter.GetLType(Index: Integer): TsgDXFLineType;
begin
  Result := TsgDXFLineType(FLTypes[Index]);
end;

function TsgDXFConverter.GetSection(Index: TConvSection): TsgDXFGroup;
begin
  Result := nil;
  if Ord(Index) > Ord(High(TConvSection)) then
    Exit;
  case Index of
    csTables:
      Result := FTablesSection;
    csBlocks:
      Result := FBlocksSection;
    csDimStyles:
      Result := FDimStyles;
    csEntities:
      Result := FEntities;
    csLTypes:
      Result := FLTypes;
    csLayers:
      Result := FLayers;
    csStyles:
      Result := FStyles;
    csVPorts:
      Result := FVPorts;
    csBlockRecords:
      Result := FBlockRecords;
    csMLineStyles:
      Result := FMStyles;
    csImageDefs:
      Result := FImageDefs;
    csLayouts:
      Result := FLayouts;
    csTableStyles:
      Result := FTableStyles;
    csObjects:
      Result := FObjectsSection;
  end;
end;

function TsgDXFConverter.GetTable(Index: Integer): TsgDXFTable;
begin
  Result := TsgDXFTable(FTablesSection[Index]);
end;

function TsgDXFConverter.GetVPort: TFPoint;
begin
  Result := ActiveVPort.ViewDirection;
end;

function TsgDXFConverter.GetVPortByIndex(const AIndex: Integer): TsgDXFVport;
begin
  Result := TsgDXFVport(FVPorts[AIndex]);
end;

function TsgDXFConverter.GetXDataProcs: TsgXDataProcs;
begin
{$IFDEF SG_BTI}
  Result := FXDataProcs;
{$ELSE}
  Result := nil;
{$ENDIF}
end;

function TsgDXFConverter.GetXRefSearchPath: string;
var
  vLength: Integer;
begin
  Result := '';
  if FXRefSearchPaths <> nil then
  begin
    Result := FXRefSearchPaths.Text;
    vLength := Length(Result);
    if (vLength > 0) and (Result[vLength] = FXRefSearchPaths.LineBreak) then
      Delete(Result, vLength, 1);
  end;
end;

function TsgDXFConverter.GetXRefSearchPaths: TStringList;
begin
  if FXRefSearchPaths = nil then
  begin
    FXRefSearchPaths := TsgStringList.Create;
    FXRefSearchPaths.LineBreak := ';';
    FXRefSearchPaths.Sorted := True;
    FXRefSearchPaths.Duplicates := dupIgnore;
  end;
  Result := FXRefSearchPaths;
end;

procedure TsgDXFConverter.ReplaceLayout(Index: Integer; ALayout: TsgDXFLayout);
var
  vOldLayout: TsgDXFLayout;
  vTmp: TsgDXFBlock;
begin
  if Index >= FLayouts.Count then
    FLayouts.AddEntity(ALayout)
  else
  begin
    vOldLayout := TsgDXFLayout(FLayouts.Entities[Index]);
    if vOldLayout.FPaperSpaceBlock <> nil then
    begin
      vTmp := ALayout.FPaperSpaceBlock;
      ALayout.PaperSpaceBlock := vOldLayout.FPaperSpaceBlock;
      vOldLayout.PaperSpaceBlock := vTmp;
      SwapEntitiesHandle(ALayout.FPaperSpaceBlock, vOldLayout.FPaperSpaceBlock);
      SwapEntitiesHandle(ALayout.FPaperSpaceBlock.BlockRecord,
        vOldLayout.FPaperSpaceBlock.BlockRecord);
    end;
    FLayouts.SetEntity(Index, ALayout);
    if vOldLayout.FPaperSpaceBlock <> nil then
    begin
      FBlocksSection.RemoveEntity(vOldLayout.FPaperSpaceBlock);
      vOldLayout.FPaperSpaceBlock.Clear(True);
      FreeAndNil(vOldLayout.FPaperSpaceBlock);
    end;
    vOldLayout.Free;
  end;
end;

{ procedure TsgDXFConverter.ResetBlockRecords;
  var
  vBlockRec: TsgDXFBlockRecord;
  vBlock: TsgDXFBlock;
  I, J: Integer;

  function TryFreeBlockReckord(const AName: string): Boolean;
  var
  vEnt: TsgDXFEntity;
  begin
  Result := False;
  if FBlocksSection.FindEntByName(AName) = nil then
  begin
  vEnt := FBlockRecords.FindEntByName(AName);
  if Assigned(vEnt) then
  begin
  FBlockRecords.RemoveEntity(vEnt);
  vEnt.Free;
  Result := True;
  end;
  end;
  end;

  begin
  for I := FBlocksSection.Count - 1 downto 0 do
  begin
  vBlock := TsgDXFBlock(FBlocksSection[I]);
  vBlock.SetConverter(Self);
  vBlockRec := TsgDXFBlockRecord(FBlockRecords.FindEntByName(vBlock.Name));
  if vBlock.BlockRecord <> vBlockRec then
  begin
  if Assigned(vBlockRec) then
  begin
  J := FBlockRecords.IndexOfEntity(vBlockRec);
  FBlockRecords.DeleteEntity(J);
  vBlock.BlockRecord.Clone(vBlockRec);
  vBlockRec.Destroy;
  end
  else
  J := FBlockRecords.Count;
  FBlockRecords.InsertEntity(J, vBlock.BlockRecord);
  end
  else
  if vBlockRec.Name <> vBlock.Name then
  vBlockRec.Name := vBlock.Name;
  end;
  TryFreeBlockReckord(sModelSpace);
  TryFreeBlockReckord(sPaperSpace);
  end; }

procedure TsgDXFConverter.ResetHandles;
var
  vSection: TConvSection;
begin
  for vSection := Low(TConvSection) to High(TConvSection) do
    if vSection <> csEntities then
      ResetHandleEntity(Sections[vSection], Self);
end;

function TsgDXFConverter.RestoreHandle(const ANode: TsgNodeSample): Int64;
begin
  Result := cnstBadHandle;
  if ANode = nil then
    Exit;
  Result := RestoreHandle(ANode.Value);
end;

function TsgDXFConverter.GetLayerByNode(const ANode: TsgNodeSample)
  : TsgDXFLayer;
begin
  if IsHandleStr(ANode.Value) then
    Result := TsgDXFLayer(Sections[csLayers].FindEntByHandle
      (ANode.ValueAsHandle))
  else
    Result := LayerByName(ANode.Value);
end;

function TsgDXFConverter.GetLineTypeByNode(const ANode: TsgNodeSample)
  : TsgDXFLineType;
begin
  if IsHandleStr(ANode.Value) then
  begin
    Result := TsgDXFLineType(Sections[csLTypes].FindEntByHandle
      (ANode.ValueAsHandle));
    if not Assigned(Result) then
      Result := LTypeByName(sContinuous);
  end
  else
    Result := LTypeByName(ANode.Value);
end;

function TsgDXFConverter.RestoreHandle(const AExtendHandle: string): Int64;
begin
  Result := GetConvExtended.RestoreHandle(AExtendHandle);
end;

procedure TsgDXFConverter.ReLoadEntities(const AReloadCircular: Boolean);
var
  I, J: Integer;
  vBlock: TsgDXFBlock;
  vEnt: TsgDXFEntity;
  vCADImage: TsgCADImage;
begin
  if FStatus <> stEditing then
  begin
    for I := 0 to Counts[csBlocks] - 1 do
    begin
      vBlock := TsgDXFBlock(FBlocksSection[I]);
      for J := 0 to vBlock.Count - 1 do
      begin
        vEnt := vBlock.Entities[J];
        if CheckEntTypeByRealod(vEnt, AReloadCircular) then
          vEnt.Loaded(Self)
        else if (vEnt is TsgDXFXref) and (TsgDXFXref(vEnt).CADImage <> nil) and
          (TsgDXFXref(vEnt).CADImage is TsgCADImage) and
          (TsgCADImage(TsgDXFXref(vEnt).CADImage).Converter <> nil) then
        begin
          vCADImage := TsgCADImage(TsgDXFXref(vEnt).CADImage);
          if AReloadCircular then
            vCADImage.Converter.NumberOfPartsInCircle := NumberOfPartsInCircle
          else
            vCADImage.Converter.NumberOfPartsInSpline := NumberOfPartsInSpline
        end;
      end;
    end;
  end;
end;

procedure TsgDXFConverter.SetSection(Index: TConvSection; Value: TsgDXFGroup);
begin
  case Index of
    // sections
    csTables:
      FTablesSection := Value as TsgDXFSection;
    csBlocks:
      FBlocksSection := Value as TsgDXFSection;
    csObjects:
      FObjectsSection := Value as TsgDXFSection;
    // tables
    csDimStyles:
      FDimStyles := Value as TsgDXFTable;
    csLTypes:
      FLTypes := Value as TsgDXFTable;
    csLayers:
      FLayers := Value as TsgDXFTable;
    csStyles:
      FStyles := Value as TsgDXFTable;
    csVPorts:
      FVPorts := Value as TsgDXFTable;
    csBlockRecords:
      FBlockRecords := Value as TsgDXFTable;
    // dictionaries
    csImageDefs:
      FImageDefs := Value as TsgDXFTable;
    csTableStyles:
      FTableStyles := Value as TsgDXFTable;
    csLayouts:
      FLayouts := Value as TsgDXFTable;
  end;
end;

function TsgDXFConverter.AddXRef(ACADFile: TObject; AName: string;
  APos, AScale: TFPoint; Rotation: Single; const ALayout: TsgDXFLayout = nil)
  : TsgDXFInsert;
var
  Insert: TsgDXFInsert;
  Xref: TsgDXFXref;
  vLoaded: Boolean;
begin
  Xref := TsgDXFXref.Create;
  Xref.SetConverter(Self);
  Insert := TsgDXFInsert.Create;
  Result := Insert;
  Insert.Layer := Self.LayerByName(HeadVarStruct.CLayer);
  Insert.Block := TsgDXFBlock.Create;
  Insert.Block.Layer := Insert.Layer;
  Xref.Layer := Insert.Block.Layer;
  if Assigned(Self.OnCreate) then
  begin
    Self.OnCreate(Insert);
    Self.OnCreate(Insert.Block);
    Self.OnCreate(Xref);
  end;
  if ACADFile is TsgCADImage then
  begin
    Xref.FCADImage := TsgCADImage(ACADFile);
    InitXRefConverter(TsgCADImage(ACADFile).Converter, Xref);
  end;
  Xref.Name := AName;
  Xref.Loaded(Self);
  Insert.Block.Name := ChangeFileExt(ExtractFileName(AName), '');
  Insert.FPoint := APos;
  Insert.FScale := AScale;
  Insert.FAngle := Rotation;
  Insert.Block.FXref := Xref;
  Insert.Block.AddEntity(Xref);
  Insert.Block.Loaded(Self);
  Insert.Block.XrefPath := AName; // correct XRef path
  Insert.Block.SetFlags(4); // correct XRef flag
  Insert.Loaded(Self);
  FBlocksSection.AddEntity(Insert.Block);
  if ALayout = nil then
    FEntities.AddEntity(Insert)
  else
  begin
    vLoaded := ALayout.PaperSpaceBlock.IsLoaded;
    try
      ALayout.PaperSpaceBlock.IsLoaded := False;
      ALayout.PaperSpaceBlock.AddEntity(Insert);
      ALayout.PaperSpaceBlock.Loaded(Self);
    finally
      ALayout.PaperSpaceBlock.IsLoaded := vLoaded;
    end;
    ALayout.FBox := ALayout.PaperSpaceBlock.Box;
  end;
end;

function TsgDXFConverter.AddXRefEx(ACADFile: TObject; AName: string;
  APos, AScale: TFPoint; Rotation: Single; ALayout: TsgDXFLayout;
  const AddXrefLayers: Boolean = True): TsgDXFInsert;
var
  Insert: TsgDXFInsert;
  Xref: TsgDXFXref;
  I: Integer;
  vLayer: TsgDXFLayer;
  vXrefConv: TsgDXFConverter;
  vName: string;
begin
  try
    vName := ChangeFileExt(ExtractFileName(AName), '');
    Insert := TsgDXFInsert.Create;
    Insert.Layer := Self.LayerByName(HeadVarStruct.CLayer);
    Insert.Block := Self.BlockByName(vName);
    if Assigned(Insert.Block) then
    begin
      Insert.Block.FXref := nil;
      Insert.Block.XrefPath := '';
      Insert.Block.Clear(True);
    end
    else
    begin
      Insert.Block := TsgDXFBlock.Create;
      Insert.Block.Name := vName;
      Insert.Block.SetFlags(0);
      FBlocksSection.AddEntity(Insert.Block);
    end;
    Insert.Block.Layer := Insert.Layer;
    Xref := TsgDXFXref.Create;
    Xref.SetOwner(Insert.Block);
    Xref.Layer := Insert.Block.Layer;
    if Assigned(Self.OnCreate) then
    begin
      Self.OnCreate(Insert);
      Self.OnCreate(Insert.Block);
      Self.OnCreate(Xref);
    end;
    vXrefConv := nil;
    if ACADFile is TsgCADImage then
    begin
      vXrefConv := TsgCADImage(ACADFile).Converter;
      Xref.FCADImage := TsgCADImage(ACADFile);
      InitXRefConverter(vXrefConv, Xref);
    end;
    Xref.Name := AName;
    Xref.Loaded(Self);
    if Assigned(vXrefConv) and AddXrefLayers then
      for I := 0 to vXrefConv.Counts[csLayers] - 1 do
        if vXrefConv.FLayers[I].Name <> '0' then
        begin
          vLayer := TsgDXFLayer.Create;
          vLayer.AssignEntity(vXrefConv.FLayers[I]);
          vLayer.Name := vName + cnstXRefNameDelimiter +
            vXrefConv.FLayers[I].Name;
          vLayer.XrefLink := True;
          vLayer.Loaded(Self);
          if FLayers = nil then
            Sections[csLayers] := NewNamedTable(cnstSectionNames[csLayers].Name,
              cnstSectionNames[csLayers].ClassType);
          FLayers.AddEntity(vLayer);
        end;
    Insert.FPoint := APos;
    Insert.FScale := AScale;
    Insert.FAngle := Rotation;
    Insert.Block.IsLoaded := False;
    Insert.Block.AddEntity(Xref);
    Insert.Block.Loaded(Self);
    Insert.Block.XrefPath := AName; // correct XRef path
    Insert.Block.SetFlags(4); // correct XRef flag
    Insert.Loaded(Self);
    ALayout.PaperSpaceBlock.IsLoaded := False;
    ALayout.PaperSpaceBlock.AddEntity(Insert);
    ALayout.PaperSpaceBlock.Loaded(Self);
    ALayout.FBox := ALayout.PaperSpaceBlock.Box;
    Result := Insert;
  except
    Result := nil;
  end;
end;

procedure TsgDXFConverter.ApplyXRecodData;
const
  COLORACI = 'COLORACI';
  COLORTRUE = 'COLORTRUE';
var
  I, J: Integer;
  vLayer: TsgDXFLayer;
  vDictionary, vDictionaryReaded: TsgDXFEntity;
  vXRecord: TsgDXFXRecord;
  S: string;
  vColor: TsgColorCAD;
  vItem: TsgDictionaryItem;
begin
  for I := 0 to FEntityDictionary.Count - 1 do
  begin
    vItem := FEntityDictionary.List^[I].Data;
    if vItem.Entity is TsgDXFLayer then
    begin
      vLayer := TsgDXFLayer(vItem.Entity);
      vDictionary := vItem.Item;
      vDictionaryReaded := Sections[csObjects].FindEntByHandle
        (vDictionary.Handle);
      vItem.Item := vDictionaryReaded;
      if Assigned(vDictionaryReaded) then
      begin
        vXRecord := TsgDXFXRecord
          (vDictionaryReaded.FindEntByName(sAcadXRecRoundTrip));
        if Assigned(vXRecord) and vXRecord.InheritsFrom(TsgDXFXRecord) then
        begin
          S := '';
          for J := 0 to vXRecord.Data.DataCount - 1 do
          begin
            case vXRecord.Data.DataType[J] of
              edtString:
                if vXRecord.Data.DataCode[J] = 102 then
                  S := vXRecord.Data.DataString[J];
              edtInt:
                begin
                  if (S = COLORTRUE) and (vXRecord.Data.DataCode[J] = 90) then
                  begin
                    vColor.Active := acRGBColor;
                    vColor.Color := BGRToRGB(vXRecord.Data.DataInt[J]);
                    vLayer.ColorCAD := vColor;
                    S := '';
                  end
                end;
              edtInt16:
                begin
                  if (S = COLORACI) and (vXRecord.Data.DataCode[J] = 70) then
                  begin
                    vColor.Active := acIndexColor;
                    vColor.Color := vXRecord.Data.DataByte[J];
                    vLayer.ColorCAD := vColor;
                    S := '';
                  end;
                end;
            end;
          end;
        end;
      end
      else
      begin
        vItem.Free;
        FEntityDictionary.Delete(I);
      end;
    end;
  end;
end;

function TsgDXFConverter.BlockByName(const AName: string): TsgDXFBlock;
begin
  Result := TsgDXFBlock(FBlocksSection.FindEntByName(AName));
end;

function TsgDXFConverter.CheckActiveVPort(const AbsHeight: Double): Boolean;
begin
  Result := False;
  if ActiveVPort <> nil then
  begin
    if ActiveVPort.ViewHeight <> 0 then
      Result := AbsHeight / ActiveVPort.ViewHeight < 1E-10
    else
      Result := True;
    if Result then
      ActiveVPort := nil;
  end;
end;

{ function TsgDXFConverter.CheckBlockByName(const ABlock: TsgDXFBlock;
  const AMaxHandle: UInt64): Integer;
  var
  I: Integer;
  vBlockPrev: TsgDXFBlock;
  vEnt: TsgDXFEntity;
  begin
  Result := 0;
  vBlockPrev := BlockByName(ABlock.Name);
  if Assigned(vBlockPrev) and (vBlockPrev.SpecPaperSpace or (vBlockPrev.Handle > AMaxHandle)) then
  begin
  if vBlockPrev.References <> nil then
  begin
  for I := vBlockPrev.References.Count - 1 downto 0 do
  begin
  vEnt := vBlockPrev.References[I];
  if vEnt is TsgDXFInsert then
  TsgDXFInsert(vEnt).Block := ABlock
  else
  begin
  if vEnt is TsgDXFDimensionStyle then
  TsgDXFDimensionStyle(vEnt).ReplaceBlock(vBlockPrev, ABlock);
  end;
  end;
  end;
  Result := 1;
  Sections[csBlocks].RemoveEntity(vBlockPrev);
  FreeAndNil(vBlockPrev);
  end;
  if Assigned(vBlockPrev) then
  begin
  Result := 2;
  ABlock.SetConverter(Self);
  ABlock.Name := ABlock.Name + '$' + IntToHex(NativeUInt(ABlock), 0);
  end;
  end; }

function TsgDXFConverter.CheckEqualHandle(const AEntity: TsgDXFEntity;
  const AHandles: TsgInt64List; const ALog: TStrings = nil): Integer;
var
  I, vCount: Integer;
  vHandle: UInt64;
begin
  Result := 0;
  if Assigned(AEntity) then
  begin
    if AEntity.Handle = cnstBadHandle then
      SetHandle(AEntity)
    else
    begin
      vCount := AHandles.Count;
      vHandle := AEntity.Handle;
      AHandles.Add(vHandle);
      if AHandles.Count = vCount then
      begin
        Inc(Result);
        while AHandles.Count = vCount do
        begin
          AEntity.Handle := cnstBadHandle;
          SetHandle(AEntity);
          if AEntity.Handle <> cnstBadHandle then
            AHandles.Add(AEntity.Handle)
          else
            Break;
        end;
        if Assigned(ALog) then
          ALog.Add(AEntity.ClassName + '(' + AEntity.EntName + ')' + ' $' +
            IntToHex(vHandle, 0) + ' = $' + IntToHex(AEntity.Handle, 0));
      end;
    end;
    for I := 0 to AEntity.Count - 1 do
      Inc(Result, CheckEqualHandle(AEntity[I], AHandles));
  end;
end;

function TsgDXFConverter.CheckEqualHandles(const ALog: TStrings = nil): Integer;
var
  vSection: TConvSection;
  vHandles: TsgInt64List;
  vEntity: TsgDXFEntity;
begin
  Result := 0;
  vHandles := TsgInt64List.Create;
  try
    vHandles.Sorted := True;
    vHandles.Duplicates := dupIgnore;
    for vSection := Low(TConvSection) to High(TConvSection) do
    begin
      vEntity := Sections[vSection];
      Inc(Result, CheckEqualHandle(vEntity, vHandles, ALog));
    end;
    Inc(Result, CheckEqualHandle(Sections[csObjects], vHandles, ALog));
  finally
    vHandles.Free;
  end;
end;

function TsgDXFConverter.CheckHandle(var AHandle: UInt64): Boolean;
begin
  Result := AHandle = cnstBadHandle;
  if Result then
  begin
    Inc(FMaxHandle);
    AHandle := FMaxHandle;
  end
  else if FMaxHandle < AHandle then
    FMaxHandle := AHandle;
end;

function TsgDXFConverter.CheckUnicode: Boolean;
begin
  Result := (Self.ImportMode = imImport) or
    (Win32Platform <> VER_PLATFORM_WIN32_NT);
end;

procedure TsgDXFConverter.CleaningLayouts(ADeletePSpace: Boolean);
var
  I: Integer;
  vLayout: TsgDXFLayout;
begin
  I := 2;
  while I <= FLayouts.Count - 1 do
  begin
    vLayout := TsgDXFLayout(FLayouts[I]);
    if vLayout.IsEmpty then
      FLayouts.DeleteEntity(I).Free
    else
      Inc(I);
  end;
  if ADeletePSpace then
    DeletePaperLayout;
end;

function TsgDXFConverter.GetCodePage: Integer;
begin
  Result := FHeadVarStruct.CodePage;
end;

function TsgDXFConverter.GetConvExtended: TsgConverterExtented;
begin
  if not Assigned(FConvExtended) then
    FConvExtended := TsgConverterExtented.Create(Self);
  Result := FConvExtended;
end;

function TsgDXFConverter.GetCircleZoomPercent: Integer;
begin
  Result := ActiveVPort.CircleZoomPercent;
end;

function TsgDXFConverter.GetDefaultLayoutIndex: Integer;
begin
  if FDefaultLayoutIndex = -1 then
  begin
    if (FHeadVarStruct.TileMode = 0) and (LayoutsCount > 1) then
      FDefaultLayoutIndex := 1
    else
      FDefaultLayoutIndex := 0;
  end;
  Result := FDefaultLayoutIndex;
end;

function TsgDXFConverter.GetLTScale: Double;
begin
  Result := FHeadVarStruct.LTScale;
end;

function TsgDXFConverter.GetPHeadVarStruct: PsgHeadVarStruct;
begin
  Result := @FHeadVarStruct;
end;

// function TsgDXFConverter.GetPaperSpace: Boolean;
// begin
// Result := False;
// end;

function TsgDXFConverter.GetPointDisplayMode: Integer;
begin
  Result := FHeadVarStruct.PointDisplayMode;
end;

class function TsgDXFConverter.GetPropertyName: string;
begin
  Result := 'Converter';
end;

function TsgDXFConverter.GetReference(AClass: TsgObjectClass; AName: string)
  : TsgListObject;
begin
  Result := nil;
  if AClass = TsgDXFLayer then
    Result := LayerByName(AName);
  if AClass = TsgDXFLineType then
    Result := LTypeByName(AName);
end;

function TsgDXFConverter.GetTextPolylines(const AText: TsgDXFText;
  const AList: TList): Integer;
begin
  Result := DXFConv.GetTextContours(Self, AText, AList);
end;

function TsgDXFConverter.GetDimStyle(Index: Integer): TsgDXFDimensionStyle;
begin
  Result := TsgDXFDimensionStyle(FDimStyles[Index]);
end;

function TsgDXFConverter.GetDisplayImageFrame: Boolean;
var
  vRasterVars: TsgCADRasterVariables;
begin
  vRasterVars := TsgCADRasterVariables
    (Sections[csObjects].FindEntByName(sRasterVariables));
  if vRasterVars <> nil then
    Result := vRasterVars.DisplayImageFrame
  else
    Result := cnstRasterVariablesDisplayImageFrame;
end;

function TsgDXFConverter.GetDWGVersion(const S: AnsiString;
  var AVersion: TsgDWGVersion): Integer;
begin
  Result := sgConsts.GetDWGVersion(S, AVersion);
end;

procedure TsgDXFConverter.SetNumberOfPartsInCircle(const ACount: Integer);
begin
  if FNumberOfPartsInCircle = ACount then
    Exit;
  FNumberOfPartsInCircle := ACount;
  if FNumberOfPartsInCircle <= 1 then
    FNumberOfPartsInCircle := GetNumberOfCircleParts;
  ReLoadEntities(True);
end;

procedure TsgDXFConverter.SetNumberOfPartsInSpline(const ACount: Integer);
begin
  if FNumberOfPartsInSpline = ACount then
    Exit;
  FNumberOfPartsInSpline := ACount;
  if FNumberOfPartsInSpline <= 1 then
    FNumberOfPartsInSpline := GetNumberOfSplineParts;
  ReLoadEntities(False);
end;

function TsgDXFConverter.ViewTwistMatrix: TFMatrix;
begin
  Result := FViewTwistMatrix;
end;

function TsgDXFConverter.RemoveEntity(AEntity: TsgDXFEntity;
  DoFree: Boolean): Boolean;
begin
  Result := False;
  if (FEntities <> nil) and FEntities.RemoveEntity(AEntity) then
  begin
    if DoFree then
      AEntity.Free;
    Result := True;
  end;
end;

function TsgDXFConverter.RemoveFromEntitiesWithGeneratedHandles
  (const AEntity: TsgDXFEntity): Boolean;
begin
  Result := False;
  if FMapEntities.HasGeneratedList then
    Result := FMapEntities.RemoveEntityFromGeneratedList(AEntity);
end;

function TsgDXFConverter.DeleteBlock(ABlock: TsgDXFBlock;
  DoFree: Boolean): Boolean;
begin
  Result := False;
  if Assigned(ExtractFromTable(FBlocksSection, ABlock)) then
  begin
    if DoFree then
      ABlock.Free;
    Result := True;
  end;
end;

function TsgDXFConverter.DeleteDimStyle(AStyle: TsgDXFDimensionStyle;
  DoFree: Boolean): Boolean;
begin
  Result := False;
  if Assigned(ExtractFromTable(FDimStyles, AStyle)) then
  begin
    if DoFree then
      AStyle.Free;
    Result := True;
  end;
end;

function TsgDXFConverter.GetSHXFonts: TsgSHXFontList;
begin
  Result := FSHXFonts;
end;

procedure TsgDXFConverter.SetCodePage(ACodePage: Integer);
begin
  FHeadVarStruct.CodePage := ACodePage;
end;

procedure TsgDXFConverter.SetDisplayImageFrame(const Value: Boolean);
var
  vRasterVars: TsgCADRasterVariables;
begin
  vRasterVars := Sections[csObjects].FindEntByName(sRasterVariables)
    as TsgCADRasterVariables;
  if vRasterVars = nil then
  begin
    vRasterVars := TsgCADRasterVariables.Create;
    Loads(vRasterVars);
    Sections[csObjects].AddEntity(vRasterVars);
  end;
  vRasterVars.DisplayImageFrame := Value;
end;

procedure TsgDXFConverter.SetHandleGroup(E: TsgDXFEntity);
var
  I: Integer;
  H: UInt64;
  vCheckHandle: Boolean;
begin
  if (Self = nil) or (E.Count = 0) then
    Exit;
  H := E.Entities[0].Handle;
  if (FStatus = stLoading) and FMapEntities.HasGeneratedList then
  begin
    if H = cnstBadHandle then
      FMapEntities.AddEntitiesToGeneratedList(E)
    else
    begin
      for I := 0 to E.Count - 1 do
      begin
        H := E.Entities[I].Handle;
        if FMaxHandle < H then
          FMaxHandle := H;
      end;
    end;
  end
  else
  begin
    for I := 0 to E.Count - 1 do
    begin
      H := E.Entities[I].Handle;
      vCheckHandle := CheckHandle(H);
      if vCheckHandle then
        E.Entities[I].Handle := H;
    end;
  end;
end;

procedure TsgDXFConverter.SetHandle(E: TsgDXFEntity);
var
  H: UInt64;
  vCheckHandle: Boolean;
begin
  if Self = nil then
    Exit;
  H := E.Handle;
  if (FStatus = stLoading) and FMapEntities.HasGeneratedList then
  begin
    if H = cnstBadHandle then
    begin
      if E.CanHaveHandle then
      begin
        E.SetConverter(Self);
        FMapEntities.AddEntityToGeneratedList(E);
      end;
    end
    else
    begin
      if FMaxHandle < H then
        FMaxHandle := H;
    end;
  end
  else
  begin
    vCheckHandle := CheckHandle(H);
    if vCheckHandle then
      E.Handle := H;
  end;
end;

procedure TsgDXFConverter.SetHandSeed(const AMaxHandle: UInt64);
begin
  FMaxHandle := AMaxHandle;
end;

procedure TsgDXFConverter.SetHideWipeouts(const Value: Boolean);
var
  vWipeoutVars: TsgCADWipeoutVariables;
begin
  vWipeoutVars := TsgCADWipeoutVariables
    (Sections[csObjects].FindEntByName(cntClassDXFWIPEOUTVARIABLES));
  if vWipeoutVars = nil then
  begin
    vWipeoutVars := TsgCADWipeoutVariables.Create;
    Loads(vWipeoutVars);
    Sections[csObjects].AddEntity(vWipeoutVars);
  end;
  vWipeoutVars.DisplayImageFrame := not Value;
end;

procedure TsgDXFConverter.AddACADLayout(ALayout: TsgDXFLayout);
var
  vPaperIndex: Integer;
  vLayoutPrev: Integer;
begin
  ALayout.SetConverter(Self);
  vPaperIndex := GetPaperIndex(ALayout.PaperSpaceBlock.Name);
  case vPaperIndex of
    0:
      ReplaceLayout(0, ALayout); // setting Model Layout
    1:
      begin
        ALayout.CADSpace := csUndefined;
        ReplaceLayout(1, ALayout); // setting Paper Layout
      end;
  else
    if Assigned(FLayouts) then
    begin
      vLayoutPrev := FLayouts.IndexOfName(ALayout.Name);
      if vLayoutPrev > 1 then
        ReplaceLayout(vLayoutPrev, ALayout)
      else
        AddLayout(ALayout)
    end
    else
      AddLayout(ALayout)
  end; { case }
end;

function TsgDXFConverter.AddDrawingLayout(ACADImage: TObject; AName: string)
  : TsgDXFLayout;
begin
  Result := TsgDXFLayout(NewNamedEntity(FLayouts, TsgDXFLayout, AName));
  Result.Loaded(Self); // by set converter
  AddXRef(ACADImage, AName, cnstFPointZero, cnstFPointSingle, 0, Result);
  Result.Loaded(Self);
end;

procedure TsgDXFConverter.AddEntitiesWithGeneratedHandles
  (const AEntity: TsgDXFEntity);
begin
  if FMapEntities.HasGeneratedList then
    FMapEntities.AddEntityToGeneratedList(AEntity);
end;

function TsgDXFConverter.AddLayout(ALayout: TsgDXFLayout): Integer;
begin
  ALayout.SetConverter(Self);
  Result := FLayouts.AddEntity(ALayout);
end;

function TsgDXFConverter.ToXML(const AParrentNode: TsgNode;
  const AMode: TsgXMLModes = cnstDefaultXMLMode): TsgNode;
const
  cnstXMLName: array [0 .. 4] of string = (cnstXMLHeader, cnstXMLTables,
    cnstXMLBlocks, cnstXMLEntities, cnstXMLObjects);
var
  I, J: Integer;
  vList: TList;
  vSection: TsgDXFSection;
  vXMLName: TStringList;
begin
  Result := inherited ToXML(AParrentNode, AMode);
  vXMLName := TStringList.Create;
  vList := TList.Create;
  try
    for I := Low(cnstXMLName) to High(cnstXMLName) do
    begin
      if SameText(cnstXMLEntities, cnstXMLName[I]) then
      begin
        if xmAddSectionEntities in AMode then
          vXMLName.Add(cnstXMLName[I]);
      end
      else
        vXMLName.Add(cnstXMLName[I]);
    end;

    GetSubEntities(vList);
    if Assigned(vList) then
      for I := 0 to vList.Count - 1 do
      begin
        vSection := TsgDXFSection(vList[I]);
        if not Assigned(vSection) then
          Continue;
        for J := 0 to vXMLName.Count - 1 do
          if SameText(vSection.Name, vXMLName[J]) then
          begin
            vSection.ToXML(Result, AMode);
            Break;
          end;
      end;
  finally
    vList.Free;
    vXMLName.Free;
  end;
end;

function TsgDXFConverter.AddLineType(const ALTypeName: string;
  const AUniform: Boolean; const ADashes: array of Double): TsgDXFEntity;
begin
  Result := nil;
  if Sections[csLTypes] <> nil then
    Result := Sections[csLTypes].FindEntByName(ALTypeName);
  if Result = nil then
  begin
    Result := CustomEntByName(ALTypeName, csLTypes);
    if Result <> nil then
    begin
      Result.Lines.Initialize(ADashes);
      Result.Lines.IsUniform := AUniform;
      Loads(Result);
    end;
  end;
end;

procedure TsgDXFConverter.FillMainSection;
begin
  if FMain <> nil then
  begin
    if Main.IndexOfEntity(Sections[csTables]) < 0 then
      Main.AddEntity(Sections[csTables]);
    if Main.IndexOfEntity(Sections[csBlocks]) < 0 then
      Main.AddEntity(Sections[csBlocks]);
    if Main.IndexOfEntity(Sections[csObjects]) < 0 then
      Main.AddEntity(Sections[csObjects]);

    if Assigned(FBlockRecords) and
      (Sections[csTables].IndexOfEntity(FBlockRecords) < 0) then
      Sections[csTables].AddEntity(FBlockRecords);
    if Assigned(FImageDefs) and
      (Sections[csObjects].IndexOfEntity(FImageDefs) < 0) then
      Sections[csObjects].AddEntity(FImageDefs);
    if Assigned(FMStyles) and (Sections[csObjects].IndexOfEntity(FMStyles) < 0)
    then
      Sections[csObjects].AddEntity(FMStyles);
    if Assigned(FLayouts) and (Sections[csObjects].IndexOfEntity(FLayouts) < 0)
    then
      Sections[csObjects].AddEntity(FLayouts);
    if Assigned(FTableStyles) and
      (Sections[csObjects].IndexOfEntity(FTableStyles) < 0) then
      Sections[csObjects].AddEntity(FTableStyles);
    if Assigned(FFieldList) and
      (Sections[csObjects].IndexOfEntity(FFieldList) < 0) then
      Sections[csObjects].AddEntity(FFieldList);
  end;
end;

function TsgDXFConverter.DeleteLayout(ALayout: TsgDXFLayout): Boolean;
begin
  Result := ALayout <> GetModelLayout;
  if Result then
    FLayouts.RemoveEntity(ALayout);
end;

function TsgDXFConverter.GetTransform3d: TFMatrix;
begin
  Result := FTransform3D;
end;

procedure TsgDXFConverter.SetTransform3d(AMatrix: TFMatrix);
begin
  FTransform3D := AMatrix;
end;

function TsgDXFConverter.GetUCS(ALayout: TsgDXFLayout): TFMatrix;
var
  Matr: TFMatrix;
  XDir, YDir, ZDir, vShift: TFPoint;

  function BuildZVector(X, Y: TFPoint): TFPoint;
  begin
    Result := MakeFPoint(X.Y * Y.Z - X.Z * Y.Y, Y.X * X.Z - X.X * Y.Z,
      X.X * Y.Y - Y.X * X.Y);
  end;

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

  begin
    Result.X := Part(0);
    Result.Y := Part(1);
    Result.Z := Part(2);
  end;

  procedure BuildMatr;
  var
    I: Integer;
  begin
    ZDir := BuildZVector(XDir, YDir);
    for I := 0 to 2 do
    begin
      Matr.M[0, I] := XDir.V[I];
      Matr.M[1, I] := YDir.V[I];
      Matr.M[2, I] := ZDir.V[I];
      Matr.M[3, I] := 0;
    end;
    vShift := PtXMat(vShift, Matr);
    for I := 0 to 2 do
      Matr.M[3, I] := -vShift.V[I];
  end;

begin
  if ALayout.IsModel then
  begin
    if not ActiveVPort.UCSVP then
    begin
      vShift := GetHeadVarAsFPt('$UCSORG');
      XDir := GetHeadVarAsFPt('$UCSXDIR');
      YDir := GetHeadVarAsFPt('$UCSYDIR');
    end
    else
    begin
      vShift := ActiveVPort.UCSOrigin;
      XDir := ActiveVPort.UCSXDir;
      YDir := ActiveVPort.UCSYDir;
    end;
  end
  else
  // if ALayout.PaperSpace = 1 then
  begin
    vShift := MakeFPoint(0, 0, 0);
    XDir := MakeFPoint(1, 0, 0);
    YDir := MakeFPoint(0, 1, 0);
  end;
  { else
    brgin
    vShift := ALayout.UCSOrigin;
    XDir := ALayout.UCSXDir;
    YDir := ALayout.UCSYDir;
    end; }
  BuildMatr;
  Result := Matr;
end;

function TsgDXFConverter.GetHeaderSection: TsgDXFSection;
begin
  if not Assigned(FHeaderSection) then
    FHeaderSection := TsgDXFSectionHeader.CreateByConverter(Self);
  Result := FHeaderSection;
end;

function TsgDXFConverter.GetHeadVarAsFPt(AName: string): TFPoint;
begin
  if AName = '$UCSORG' then
    Result := FHeadVarStruct.UCSORG
  else if AName = '$UCSXDIR' then
    Result := FHeadVarStruct.UCSXDir
  else if AName = '$UCSYDIR' then
    Result := FHeadVarStruct.UCSYDir;
end;

function TsgDXFConverter.GetHideWipeouts: Boolean;
var
  vWipeoutVars: TsgCADWipeoutVariables;
begin
  vWipeoutVars := TsgCADWipeoutVariables
    (Sections[csObjects].FindEntByName(cntClassDXFWIPEOUTVARIABLES));
  if vWipeoutVars <> nil then
    Result := not vWipeoutVars.DisplayImageFrame
  else
    Result := not cnstWipeoutVariablesDisplayImageFrame;
end;

procedure TsgDXFConverter.InitializeSections;
begin
  InitializeSectionsBegin;
end;

procedure TsgDXFConverter.InitializeSectionsBegin;
var
  I: TConvSection;
begin
  for I := csLTypes to csVPorts do
    if I <> csEntities then
      Sections[I] := NewTable(I);
  FillMainSection;
end;

procedure TsgDXFConverter.InitXRefConverter(const AXRefConv: TsgDXFConverter;
  const AXRef: TsgDXFXref);
begin
  if Assigned(AXRefConv) then
  begin
    AXRefConv.FContainerXref := AXRef;
    AXRefConv.FOwnerConverter := Self;
  end;
end;

procedure TsgDXFConverter.InitializeSectionsEnd;
var
  I: TConvSection;
  J: Integer;
  vLayers: TsgDXFGroup;
  vLineType: TsgDXFLineType;
  vDimStyle: TsgDXFDimensionStyle;
begin
  if Self.Sections[csLTypes] = nil then
    Sections[csLTypes] := NewNamedTable(cnstSectionNames[csLTypes].Name,
      cnstSectionNames[csLTypes].ClassType);
  CustomEntByName(sByLayer, csLTypes);
  CustomEntByName(sByBlock, csLTypes);
  CustomEntByName(sContinuous, csLTypes);
  CustomEntByName(HeadVarStruct.TextStyle, csStyles);
  vDimStyle := TsgDXFDimensionStyle(CustomEntByName(HeadVarStruct.DimStyle,
    csDimStyles));
  if not Assigned(vDimStyle.DIMTXSTY) then
    vDimStyle.DIMTXSTY :=
      TsgDXFStyle(CustomEntByName(HeadVarStruct.DimTextStyle, csStyles));
  if Self.StyleByName(sStandardName) = nil then
  begin
  end;
  if Self.DimensionStyleByName(sStandardName) = nil then
  begin
  end;
  for I := csTables to csVPorts do
    if I <> csEntities then
    begin
      if Sections[I] = nil then
        Sections[I] := NewTable(I);
      TsgDXFTable(Sections[I]).Loaded(Self);
    end;
  vLineType := LTypeByName(sContinuous);
  vLayers := Sections[csLayers];
  for J := 0 to vLayers.Count - 1 do
    if (vLayers.Entities[J].LineType = nil) then
      vLayers.Entities[J].LineType := vLineType;
  if (LayoutsCount > 1) and (Layouts[1] <> nil) then
    CleaningLayouts(Layouts[1].IsEmpty);
  FreeEntitiesWithGeneratedHandles;
end;

function TsgDXFConverter.FindEntityByHandle(const AHandle: UInt64)
  : TsgDXFEntity;
begin
  Result := Sections[csEntities].FindEntByHandle(AHandle);
end;

function TsgDXFConverter.FindObjByHandle(const AHandle: UInt64): TsgDXFEntity;
begin
  FMapEntities.ActivateRegister;
  Result := FMapEntities.GetEntityByHandle(AHandle);
end;

function TsgDXFConverter.FindObjByHandles(const AHandles: TsgInt64List;
  const AEntities: TList; const AGroup: TsgDXFEntity = nil): Integer;

  procedure FindInHandles(const ASection: TsgDXFEntity;
    const AHandlesCur: TsgInt64List; const AEntities: TList);
  var
    J, vIndex: Integer;
    vHandle: UInt64;
    vEntity: TsgDXFEntity;
  begin
    for J := 0 to ASection.Count - 1 do
    begin
      vIndex := -1;
      vEntity := ASection.Entities[J];
      vHandle := vEntity.Handle;
      if vHandle > AHandlesCur.First then
      begin
        if vHandle < AHandlesCur.Last then
          vIndex := AHandlesCur.IndexOf(vHandle)
        else if vHandle = AHandlesCur.Last then
          vIndex := AHandlesCur.Count - 1;
      end
      else
      begin
        if vHandle = AHandlesCur.First then
          vIndex := 0;
      end;
      if vIndex > -1 then
      begin
        AEntities.Add(vEntity);
        AHandlesCur.Delete(vIndex);
        if AHandlesCur.Count < 1 then
          Break;
      end
      else
      begin
        if vEntity.Count > 0 then
        begin
          FindInHandles(vEntity, AHandlesCur, AEntities);
          if AHandlesCur.Count < 1 then
            Break;
        end;
      end;
    end;
  end;

var
  I: Integer;
  vSection: TsgDXFGroup;
  vHandles: TsgInt64List;
begin
  Result := AEntities.Count;
  vHandles := TsgInt64List.Create;
  try
    vHandles.AppendDynArray(AHandles);
    vHandles.ProcCompare := sgComparer.TsgPointerTypeComparer.CmpUInt64;
    if not AHandles.Sorted then
      vHandles.Sorted := True;
    if Assigned(AGroup) then
      FindInHandles(AGroup, vHandles, AEntities)
    else
    begin
      for I := Low(cnstSectionsByFindObject)
        to High(cnstSectionsByFindObject) do
      begin
        vSection := Sections[cnstSectionsByFindObject[I]];
        if not Assigned(vSection) then
          Continue;
        FindInHandles(vSection, vHandles, AEntities);
        if vHandles.Count = 0 then
          Break;
      end;
    end;
  finally
    Result := AEntities.Count - Result;
    vHandles.Free;
  end;
end;

function TsgDXFConverter.FindObjByHandles(const AHandles: TList;
  const AEntities: TList; const AGroup: TsgDXFEntity = nil): Integer;
var
  I: Integer;
  vHandles: TsgInt64List;
begin
  vHandles := TsgInt64List.Create;
  try
    vHandles.Capacity := AHandles.Count;
    for I := 0 to AHandles.Count - 1 do
      vHandles.Add(PInt64(AHandles[I])^);
    vHandles.ProcCompare := sgComparer.TsgPointerTypeComparer.CmpUInt64;
    vHandles.Sorted := True;
    Result := FindObjByHandles(vHandles, AEntities, AGroup);
  finally
    vHandles.Free;
  end;
end;

procedure TsgDXFConverter.HeadVarStructInit;
begin
  FHeadVarStruct := cnstDefHeadVarStruct;
end;

// procedure TsgDXFConverter.SetPaperSpace(const AValue: Boolean);
// begin
//
// end;

procedure TsgDXFConverter.SetPointDisplayMode(const Value: Integer);
begin
  FHeadVarStruct.PointDisplayMode := Value;
end;

procedure TsgDXFConverter.SetLTScale(const Value: Double);
begin
  FHeadVarStruct.LTScale := Value;
end;

function TsgDXFConverter.GetIs3D: Boolean;
begin
  Result := (VPort.X <> 0) or (VPort.Y <> 0);
end;

{ TsgDXFEntity }

procedure TsgDXFEntity.Clear(const ADoFree: Boolean = True);
begin
end;

procedure TsgDXFEntity.ClearReferences;
begin
  GroupClear; // clear group (after export)
  Dictionary := nil;
  LineType := nil;
  Layer := nil;
  SetConverter(nil);
end;

procedure TsgDXFEntity.GroupClear;
begin
end;

procedure TsgDXFEntity.Clone(const Source: TsgDXFEntity);
begin
  AssignEntity(Source);
  Handle := Source.Handle;
end;

constructor TsgDXFEntity.Create;
begin
{$IFDEF SG_MODULE_LOG}
  Log.Add('$' + IntToHex(TsgNativeUInt(Self), 0) + ' := ' + ClassName +
    '.Create;');
{$ENDIF}
  LineWeight := fLineWeightByLayer;
end;

function TsgDXFEntity.GroupCreate(AConverter: TsgDXFConverter = nil): Boolean;
begin
  Result := False;
end;

function TsgDXFEntity.AddEntUseInsert(const AEntity: TsgDXFEntity): Integer;
begin
  Result := Count;
  if not InsertEntity(Result, AEntity) then
    Result := -1;
end;

function TsgDXFEntity.AddHandleItem(const AItem: TsgDXFEntity): Integer;
begin
  Result := -1;
end;

function TsgDXFEntity.AddItem(const AItem: TsgDXFEntity): Integer;
begin
  Result := -1;
end;

function TsgDXFEntity.ToXML(const AParrentNode: TsgNode;
  const AMode: TsgXMLModes = cnstDefaultXMLMode): TsgNode;
begin
  Result := inherited ToXML(AParrentNode, AMode);
  ToXMLSubEntities(Result, AMode);
end;

function TsgDXFEntity.AddEntity(const AEntity: TsgDXFEntity): Integer;
// overridden in BLOCK, POLYLINE etc.
begin
  Result := AddEntUseInsert(AEntity);
end;

function TsgDXFEntity.DeleteEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := nil;
end;

function TsgDXFEntity.DeleteHandleItem(const AItem: TsgDXFEntity): Integer;
begin
  Result := -1;
end;

function TsgDXFEntity.DeleteItem(const AItem: TsgDXFEntity): Integer;
begin
  Result := -1;
end;

destructor TsgDXFEntity.Destroy;
begin
  // clear subentities
  Clear;
  // clear references to layer, linetype, blockrecord...
  ClearReferences;
  inherited Destroy;
end;

procedure TsgDXFEntity.EndExtData(const AData: TsgCADExtendedData);
begin
end;

function TsgDXFEntity.EntName: string;
begin
  Result := GetClassEntName(Self);
end;

procedure TsgDXFEntity.ExchangeEntity(AIndex1, AIndex2: Integer);
var
  vTmp: TsgDXFEntity;
begin
  vTmp := Entities[AIndex1];
  SetEntity(AIndex1, Entities[AIndex2]);
  SetEntity(AIndex2, vTmp);
end;

function TsgDXFEntity.FindEntByHandle(const AHandle: UInt64;
  const AIterateChildren: Boolean = False;
  const AIterateInsert: Boolean = False): TsgDXFEntity;
var
  I, vIndex: Integer;
begin
  Result := nil;
  vIndex := IndexOfHandle(AHandle);
  if vIndex > -1 then
    Result := Entities[vIndex]
  else
  begin
    if AIterateChildren then
    begin
      for I := 0 to Count - 1 do
      begin
        Result := Entities[I].FindEntByHandle(AHandle, True, AIterateInsert);
        if Assigned(Result) then
          Break;
      end;
      if AIterateInsert and (not Assigned(Result)) and IsInsert then
      begin
        if Assigned(TsgDXFInsert(Self).Block) then
          Result := TsgDXFInsert(Self).Block.FindEntByHandle(AHandle, True,
            AIterateInsert);
      end;
    end;
  end;
end;

function TsgDXFEntity.FindEntByName(const AName: string): TsgDXFEntity;
var
  vIndex: Integer;
begin
  Result := nil;
  vIndex := IndexOfName(AName);
  if vIndex > -1 then
    Result := Entities[vIndex];
end;

procedure TsgDXFEntity.FreeInstance;
begin
  // free object-fields created by this entity
  FreeReferences;
{$IFDEF SG_CALC_INSTANCE_SIZES}
  Dec(TotalAllocated, InstanceSize);
{$ENDIF}
  inherited FreeInstance;
end;

procedure TsgDXFEntity.FreeReferences;
begin
end;

function TsgDXFEntity.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  vLineWeight: Double;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlHandle:
      SetHandle(ANode.ValueAsHandle);
    xmlHandleSave:
      begin
        if Assigned(Converter) then
          Converter.SaveHandle(ANode.ValueAsStr, Self);
      end;
    xmlLineWeight:
      begin
        vLineWeight := ANode.ValueAsDouble;
        if vLineWeight < 0 then
        begin
          if (vLineWeight = fLineWeightByBlock) or
            (vLineWeight = fLineWeightByLayer) or
            (vLineWeight = fLineWeightDefault) then
            LineWeight := vLineWeight
          else
          begin
            Result := cnstXML_ERROR;
            DoErrorXMLNode(AResult.Errors, False, ANode, xmlLineWeight);
          end;
        end
        else
        begin
          LineWeight := ConvertLineWeightToDXF(vLineWeight) / 100;
        end;
      end;
    xmlFlags:
      SetFlags(ANode.ValueAsInt);
    xmlLineTypeName:
      begin
        if Assigned(Converter) then
          LineType := Converter.GetLineTypeByNode(ANode);
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFEntity.FromXMLSubEntities(const ANode: TsgNodeSample;
  const AResult: IsgResultNode = nil): Integer;
var
  I: Integer;
  vChild, vHandle, vName: TsgNodeSample;
  vEntity: TsgDXFEntity;
  vEntityClass: TsgDXFEntityClass;

  procedure AddHandleToResult(const AOutput: TsgNode; AName: string;
    AHandle: UInt64; ANodeChild: TsgNodeSample);
  var
    vNodeOutput: TsgNode;
    vNodeAttrib: TsgNodeSample;
  begin
    if AHandle <> cnstBadHandle then
    begin
      vNodeOutput := AOutput.AddChildNV(AName);
      vNodeAttrib := vNodeOutput.AddAttribNV(cnstXMLNames[xmlHandle].Name);
      vNodeAttrib.ValueAsHandle := AHandle;
      if vChild.HasPosition then
        vNodeOutput.AddAttribNV(cnstXMLPosition).ValueData.ValueAsPoint :=
          Point(ANodeChild.Position.X, ANodeChild.Position.Y);
    end;
  end;

begin
  Result := inherited FromXMLSubEntities(ANode, AResult);
  if ANode.ChildNodesCount > 0 then
  begin
    Result := cnstXML_OK;
    for I := 0 to ANode.ChildNodesCount - 1 do
    begin
      vEntity := nil;
      vChild := ANode.ChildNodes[I];
      vHandle := vChild.GetAttributeByName
        (sgConsts.cnstXMLNames[xmlHandle].Name);
      if Assigned(vHandle) then
      begin
        if vHandle.ValueAsHandle <> cnstBadHandle then
          vEntity := FindEntByHandle(vHandle.ValueAsHandle, False);
      end
      else
      begin
        vName := vChild.GetAttributeByName(sgConsts.cnstXMLNames[xmlName].Name);
        if Assigned(vName) then
        begin
          if Length(vName.ValueAsStr) > 0 then
            vEntity := FindEntByName(vName.ValueAsStr);
        end;
      end;
      if Assigned(vEntity) then // set
      begin
        vEntity.SetConverter(Converter);
        if vEntity is TsgDXFBlock then
          TsgDXFBlock(vEntity).IsLoaded := False;
        vEntity.FromXML(vChild, AResult);
        AddHandleToResult(AResult.Output, cnstXMLUpdated,
          vEntity.Handle, vChild);
      end
      else // added
      begin
        vEntityClass := TsgDXFEntityClass(GetClassByXMLName(vChild.Name));
        if Assigned(vEntityClass) then
        begin
          vEntity := vEntityClass.Create;
          vEntity.SetConverter(Converter);
          // Initialize entity by active layer (http://192.168.0.102/bugzilla/show_bug.cgi?id=3113)
          vEntity.Layer := Converter.LayerByName
            (Converter.HeadVarStruct.CLayer);
          AddEntity(vEntity);
          if vEntity.FromXML(vChild, AResult) <> cnstXML_OK then
            RemoveEntity(vEntity)
          else
          begin
            if AResult <> nil then
              AddHandleToResult(AResult.Output, cnstXMLCreated,
                vEntity.Handle, vChild);
          end;
        end
        else
          DoErrorXMLNode(AResult.Errors, True, vChild, xmlUndefined);
      end;
    end;
  end;
end;

function TsgDXFEntity.GetColor: TColor;
begin
  Result := ConvertColorCADToRGB(ColorCAD);
end;

function TsgDXFEntity.GetColorCAD: TsgColorCAD;
begin
  Result := cnstDefHeadVarStruct.CEColor;
end;

function TsgDXFEntity.GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean;
var
  R: TFRect;
begin
  Result := False;
  R := GetBox;
  if IsBadRect(R) then
    Exit;
  Proc(R.TopLeft);
  Proc(R.BottomRight);
  if not Full then
    Exit;
  Proc(MakeFPoint(R.Left, R.Top, R.Z2));
  Proc(MakeFPoint(R.Left, R.Bottom, R.Z1));
  Proc(MakeFPoint(R.Left, R.Bottom, R.Z2));
  Proc(MakeFPoint(R.Right, R.Top, R.Z1));
  Proc(MakeFPoint(R.Right, R.Top, R.Z2));
  Proc(MakeFPoint(R.Right, R.Bottom, R.Z1));
end;

function TsgDXFEntity.GetVisible: Boolean; // is on visible layer
begin
  Result := ((Layer = nil) or (not Layer.Frozen and Layer.Visible)) and
    Visibility;
end;

function TsgDXFEntity.GetBox: TFRect; // overridden in all visible descendants
begin
  Result := BadRect;
end;

function TsgDXFEntity.GetCount: Integer;
begin
  Result := 0;
end;

function TsgDXFEntity.GetDictionary: TsgDXFEntity;
var
  I: Integer;
  vConverter: TsgDXFConverter;
begin
  Result := nil;
  if Handle <> cnstBadHandle then
  begin
    vConverter := Converter;
    if Assigned(vConverter) and Assigned(vConverter.FEntityDictionary) then
    begin
      I := vConverter.FEntityDictionary.IndexOf(Handle);
      if I >= 0 then
        Result := TsgTableItem(vConverter.FEntityDictionary[I].Data).Item;
    end;
  end;
end;

function TsgDXFEntity.GetDimStyleInternal: Pointer;
begin
  Result := cnstObjectReserve;
end;

function TsgDXFEntity.GetEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := nil;
end;

function TsgDXFEntity.IndexOfEntity(const AEntity: TsgDXFEntity): Integer;
begin
  Result := Count - 1;
  while (Result >= 0) and (Entities[Result] <> AEntity) do
    Dec(Result);
end;

function TsgDXFEntity.IndexOfHandle(const AHandle: UInt64): Integer;
begin
  Result := Count - 1;
  while (Result >= 0) and (Entities[Result].Handle <> AHandle) do
    Dec(Result);
end;

function TsgDXFEntity.IndexOfName(const AName: string): Integer;
begin
  Result := Count - 1;
  while (Result >= 0) and (AnsiCompareText(Entities[Result].Name,
    AName) <> 0) do
    Dec(Result);
end;

function TsgDXFEntity.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  Result := False;
end;

procedure TsgDXFEntity.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
begin
  if IsInvoke(AConverter) then
    Proc(Self);
end;

function TsgDXFEntity.IsInvoke(AConverter: TsgDXFConverter): Boolean;
begin
  Result := True;
  if (AConverter.ImportMode = imImport) and AConverter.FViewPortCut then
    Result := (IntersectRects(GetBox, AConverter.FViewPortRect,
      AConverter.Params.Matrix) <> -1);
end;

function TsgDXFEntity.GetTextStyleInternal: Pointer;
begin
  Result := cnstObjectReserve;
end;

function TsgDXFEntity.GetThickness: Double;
begin
  Result := 0.0;
end;

function TsgDXFEntity.GroupHasAddedEntities: Boolean;
begin
  Result := False;
end;

function TsgDXFEntity.HasDimesionStyle(const AStyle: Pointer): Boolean;
begin
  Result := HasObject(AStyle, GetDimStyleInternal);
end;

function TsgDXFEntity.HasTextStyle(const AStyle: Pointer): Boolean;
begin
  Result := HasObject(AStyle, GetTextStyleInternal);
end;

function TsgDXFEntity.HasLineWeight: Boolean;
begin
  Result := True;
end;

function TsgDXFEntity.GroupExists: Boolean;
begin
  Result := False;
end;

function TsgDXFEntity.IsInsert: Boolean; // evg
begin
  Result := False;
end;

function TsgDXFEntity.IsOnePixelOptimisationValid: Boolean; // evg
begin
  Result := True;
end;

function TsgDXFEntity.GetComplex: Boolean;
begin
  Result := False;
end;

function TsgDXFEntity.GetLayer: TsgDXFLayer;
begin
  Result := nil;
end;

function TsgDXFEntity.GetLineType: TsgDXFLineType;
begin
  Result := nil;
end;

function TsgDXFEntity.GetLineTypeScale: Double;
begin
  Result := 1;
end;

function TsgDXFEntity.GetLineWeight: Double;
begin
  Result := fLineWeightByLayer;
end;

function TsgDXFEntity.GetLineWeightScaled: Boolean;
begin
  Result := False;
end;

function TsgDXFEntity.GetName: string;
begin
  Result := EntName;
end;

function TsgDXFEntity.GetNamedItem: TObject;
begin
  Result := nil;
end;

function TsgDXFEntity.GetConverter: TsgDXFConverter;
var
  vOwner: TsgDXFEntity;
begin
  vOwner := GetOwner;
  if Assigned(vOwner) then
    Result := vOwner.GetConverter()
  else
    Result := nil;
end;

function TsgDXFEntity.GetEntType: TsgCADEntities;
begin
  Result := ceEntity;
end;

function TsgDXFEntity.GetEntTypeEx: Integer;
begin
  Result := cnstUndefined;
end;

function TsgDXFEntity.GetEntClassEx: TsgEntClass;
begin
  Result.EG := gtCAD;
  Result.ET.CAD := GetEntType;
end;

function TsgDXFEntity.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
var
  vFlags: Integer;
  vHandle: UInt64;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  if IsFullPropsOrXMLHelp(AMode) or (LineWeight <> fLineWeightByLayer) then
    ANode.AddAttribNV(cnstXMLNames[xmlLineWeight].Name).ValueAsDouble :=
      LineWeight;
  vHandle := Handle;
  if (vHandle <> cnstBadHandle) or IsXMLHelp(AMode) then
    ANode.AddAttribNV(cnstXMLNames[xmlHandle].Name).ValueAsHandle := vHandle;
  vFlags := GetFlags;
  if IsFullPropsOrXMLHelp(AMode) or (vFlags <> 0) then
    ANode.AddAttribNV(cnstXMLNames[xmlFlags].Name).ValueAsInt := vFlags;
  if IsXMLHelp(AMode) then
  begin
    ANode.AddAttribNV(cnstXMLNames[xmlLineTypeName].Name);
  end
  else if Assigned(LineType) and
    (IsFullProps(AMode) or (LineType.Name <> sByLayer)) then
    ANode.AddAttribNV(cnstXMLNames[xmlLineTypeName].Name).Value :=
      LineType.Name;
end;

procedure TsgDXFEntity.ToXMLSubEntities(const AParrentNode: TsgNode;
  const AMode: TsgXMLModes = cnstDefaultXMLMode);
var
  I: Integer;
  vSubEntities: TsgNode;
  vMode: TsgXMLModes;
begin
  if (xmAddSubEntities in AMode) and (Count > 0) then
  begin
    if not(xmNoSubEntitiesNode in AMode) then
      vSubEntities := AParrentNode.AddChildNV(cnstXMLNames[xmlSubEntities].Name)
    else
      vSubEntities := AParrentNode;
    vMode := AMode;
    if xmOnlyChildNodes in vMode then
      Exclude(vMode, xmAddSubEntities);
    for I := 0 to Count - 1 do
      Entities[I].ToXML(vSubEntities, vMode);
  end;
end;

function TsgDXFEntity.GetExtData(const AData: TsgCADExtendedData): Boolean;
begin
  Result := False;
end;

function TsgDXFEntity.GetExtrusion: TFPoint;
begin
  Result := cnstExtrusion;
end;

function TsgDXFEntity.GetFlags: Integer;
begin
  Result := 0;
end;

function TsgDXFEntity.GroupGet: TsgDXFGroup;
begin
  Result := nil;
end;

function TsgDXFEntity.GetHandle: UInt64;
begin
  Result := cnstBadHandle;
end;

function TsgDXFEntity.GetInternalFlags: Byte;
begin
  Result := 0;
end;

function TsgDXFEntity.GetOnDraw: TNotifyEvent;
begin
  Result := nil;
end;

function TsgDXFEntity.GetOwner: TsgDXFEntity;
begin
  Result := nil;
end;

function TsgDXFEntity.GetPaperSpace: Integer;
begin
  Result := 0;
end;

function TsgDXFEntity.GetSrcEnd: PAnsiChar;
begin
  Result := nil;
end;

function TsgDXFEntity.GetSrcStart: PAnsiChar;
begin
  Result := nil;
end;

function TsgDXFEntity.GetVisibility: Boolean;
begin
  Result := True;
end;

procedure TsgDXFEntity.AssignEntity(Source: TsgDXFEntity);
begin
  if Assigned(Source) and (Source.ClassType <> TsgLinkObject) then
  begin
    LineWeight := Source.LineWeight;
    LineTypeScale := Source.LineTypeScale;
  end;
end;

function TsgDXFEntity.BeginExtData(const AData: TsgCADExtendedData): Boolean;
begin
  Result := False;
end;

function TsgDXFEntity.RemoveEntity(const AEntity: TsgDXFEntity): Boolean;
var
  vIndex: Integer;
begin
  Result := False;
  vIndex := IndexOfEntity(AEntity);
  while vIndex > -1 do
  // Removes some times added primitives. Error correction is added.
  begin
    DeleteEntity(vIndex);
    Result := True;
    vIndex := IndexOfEntity(AEntity);
  end;
end;

procedure TsgDXFEntity.RemoveReferenceNotification(const ARefObj: TsgDXFEntity);
begin
end;

procedure TsgDXFEntity.Draw;
begin // do nothing
end;

procedure TsgDXFEntity.Link(AConverter: TsgDXFConverter);
begin
end;

procedure TsgDXFEntity.ListNotify(Ptr: Pointer; Action: TListNotification);
var
  vConverter: TsgDXFConverter;
begin
  vConverter := GetConverter;
  if Assigned(vConverter) then
    vConverter.EntityListNotify(Ptr, Action);
end;

procedure TsgDXFEntity.Loaded(AConverter: TsgDXFConverter);
begin
  ChangeHandle(AConverter);
  SetConverter(AConverter);
  LoadedInternal(AConverter);
end;

procedure TsgDXFEntity.EntityLoaded;
begin
  inherited EntityLoaded;
  if Assigned(Converter) then
    Loaded(Converter);
end;

procedure TsgDXFEntity.LoadedInternal(AConverter: TsgDXFConverter);
begin
{$IFDEF SG_MODULE_LOG}
  Log.Add(ClassName + '($' + IntToHex(TsgNativeUInt(Self), 0) + ').Loaded');
{$ENDIF}
end;

{$IFDEF SG_CALC_INSTANCE_SIZES}

class function TsgDXFEntity.NewInstance: TObject;
begin
  Result := inherited NewInstance;
  Inc(TotalAllocated, InstanceSize);
end;
{$ENDIF}

function TsgDXFEntity.CanDraw: Boolean;
begin
  Result := False;
end;

function TsgDXFEntity.CanHaveHandle: Boolean;
begin
  Result := False;
end;

procedure TsgDXFEntity.ChangeHandle(AConverter: TsgDXFConverter);
begin
  AConverter.SetHandle(Self);
end;

procedure TsgDXFEntity.SetColor(Value: TColor);
begin
  SetColor__(Value);
end;

procedure TsgDXFEntity.SetColorCAD(const Value: TsgColorCAD);
begin // do nothing
end;

procedure TsgDXFEntity.SetColor__(const Value: TColor);
begin
  ColorCAD := ConvertColortoColorCAD(Value);
end;

procedure TsgDXFEntity.SetConverter(const AConverter: TsgDXFConverter);
begin // do nothing
end;

procedure TsgDXFEntity.SetDictionary(const AValue: TsgDXFEntity);
var
  I: Integer;
  vConverter: TsgDXFConverter;
  vItem: TsgDictionaryItem;
  vCollection: TsgCollection;
begin
  if Handle <> cnstBadHandle then
  begin
    vConverter := Converter;
    if (vConverter = nil) and Assigned(AValue) then
      vConverter := AValue.Converter;
    if vConverter <> nil then
    begin
      vCollection := vConverter.FEntityDictionary;
      if Assigned(vCollection) then
      begin
        I := vCollection.IndexOf(Handle);
        if I >= 0 then
        begin
          vItem := TsgDictionaryItem(vCollection.List^[I].Data);
          vItem.Item := AValue;
          if AValue = nil then
          begin
            vCollection.Delete(I);
            vItem.Free;
          end;
        end
        else if AValue <> nil then
        begin
          vItem := TsgDictionaryItem.Create(Self);
          vCollection.Add(Handle, vItem);
          vItem.Item := AValue;
        end;
      end;
    end;
  end;
end;

procedure TsgDXFEntity.SetEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity);
begin // do nothing
end;

procedure TsgDXFEntity.SetExtData(const AData: TsgCADExtendedData);
begin // do nothing
end;

procedure TsgDXFEntity.SetExtrusion(const Value: TFPoint);
begin // do nothing
end;

procedure TsgDXFEntity.SetFlags(const Value: Integer);
begin
end;

procedure TsgDXFEntity.SetHandle(const Value: UInt64);
begin // do nothing
{$IFDEF SG_MODULE_LOG}
  Log.Add(ClassName + '($' + IntToHex(TsgNativeUInt(Self), 0) + ').Handle := $'
    + IntToHex(Value, 0) + ';');
{$ENDIF}
end;

procedure TsgDXFEntity.SetInternalFlags(const Value: Byte);
begin // do nothing
end;

procedure TsgDXFEntity.SetLayer(const Value: TsgDXFLayer);
begin // do nothing
end;

procedure TsgDXFEntity.SetLineType(const AValue: TsgDXFLineType);
begin // do nothing
end;

procedure TsgDXFEntity.SetLineTypeScale(Value: Double);
begin // do nothing
end;

procedure TsgDXFEntity.SetLineWeight(Value: Double);
begin // do nothing
end;

procedure TsgDXFEntity.SetLineWeightScaled(Value: Boolean);
begin // do nothing
end;

procedure TsgDXFEntity.SetLType(Value: TsgDXFEntity);
begin // for compatibility with previous versions
  if Value is TsgDXFLineType then
    LineType := TsgDXFLineType(Value)
  else
    LineType := nil;
end;

procedure TsgDXFEntity.SetLWeight(Value: Integer);
begin // do nothing
end;

procedure TsgDXFEntity.SetName(const AName: string);
begin // do nothing
end;

procedure TsgDXFEntity.SetOnDraw(const Value: TNotifyEvent);
begin // do nothing
end;

procedure TsgDXFEntity.SetOwner(const Value: TsgDXFEntity);
begin // do nothing
end;

procedure TsgDXFEntity.SetPaperSpace(const Value: Integer);
begin // do nothing
end;

procedure TsgDXFEntity.SetSrcEnd(const Value: PAnsiChar);
begin // do nothing
end;

procedure TsgDXFEntity.SetSrcStart(const Value: PAnsiChar);
begin // do nothing
end;

procedure TsgDXFEntity.SetVisibility(const Value: Boolean);
begin // do nothing
end;

procedure TsgDXFEntity.SetVisible(Value: Boolean);
begin // do nothing
end;

procedure TsgDXFEntity.StyleChanged(Sender: TObject);
begin
end;

function TsgDXFEntity.GetLineCap: Word;
begin // do nothing
  Result := PS_ENDCAP_ROUND;
end;

function TsgDXFEntity.GetLineJoin: Word;
begin
  Result := PS_JOIN_ROUND;
end;

function TsgDXFEntity.GetLines: TsgLines;
begin
  Result := StdLines;
end;

procedure TsgDXFEntity.SetLineCap(const Value: Word);
begin // do nothing
end;

procedure TsgDXFEntity.SetLineJoin(const Value: Word);
begin // do nothing
end;

{ TsgDXFEntitySample }

constructor TsgDXFEntitySample.Create;
begin
  inherited Create;
end;

function TsgDXFEntitySample.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlLineTypeScale:
      LineTypeScale := ANode.ValueAsDouble;
    xmlLayerName:
      begin
        if Assigned(Converter) then
          Layer := Converter.GetLayerByNode(ANode);
        if not Assigned(Layer) then
          Result := cnstXML_UNSUPPORTED;
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure TsgDXFEntitySample.CheckArroyType(const AValue: TsgDimArrowType);
var
  vBlock: TsgDXFBlock;
begin
  if FConverter <> nil then
  begin
    vBlock := FConverter.BlockByName(sgDimensionArrowTypeNames[AValue]);
    if vBlock = nil then
    begin
      vBlock := TsgDXFBlock.Create;
      vBlock.Layer := GetLayer;
      GenerateArrow(FConverter, vBlock, AValue);
      vBlock.Name := sgDimensionArrowTypeNames[AValue];
      vBlock.Loaded(FConverter);
      FConverter.FBlocksSection.AddEntity(vBlock);
    end;
  end;
end;

procedure TsgDXFEntitySample.AssignEntity(Source: TsgDXFEntity);
var
  vEntitySample: TsgDXFEntitySample absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFEntitySample then
  begin
    FTextRotation := vEntitySample.FTextRotation;
    FBackGroundImage := vEntitySample.FBackGroundImage;
  end;
end;

function TsgDXFEntitySample.GetBackGroundImage: TsgDXFImageEnt;
begin
  Result := FBackGroundImage;
end;

function TsgDXFEntitySample.GetColorCAD: TsgColorCAD;
begin
  Result := GetActiveHeadVar^.CEColor;
end;

function TsgDXFEntitySample.GetDimTextOffset: Double;
begin
  Result := GetActiveHeadVar^.DimProps.GAP;
end;

function TsgDXFEntitySample.GetDimTextPosVert: TsgDimTextPosVert;
begin
  Result := TsgDimTextPosVert(GetActiveHeadVar^.DimProps.Tad);
end;

function TsgDXFEntitySample.GetFilletRadius: Double;
begin
  Result := GetActiveHeadVar^.FilletRadius;
end;

function TsgDXFEntitySample.GetFontHeight: TsgFloat;
begin
  Result := GetActiveHeadVar^.TextSize;
end;

function TsgDXFEntitySample.GetFontName: string;
var
  vTextStyle: TsgDXFStyle;
  vExt: string;
begin
  Result := '';
  vTextStyle := TextStyle;
  if vTextStyle <> nil then
  begin
    Result := vTextStyle.FontName;
    if Length(Result) = 0 then
    begin
      Result := vTextStyle.GetPrimaryFontName;
      if Length(Result) > 0 then
      begin
        vExt := ExtractFileExt(Result);
        if Length(vExt) > 0 then
          SetLength(Result, Length(Result) - Length(vExt));
      end;
    end;
  end;
  if Length(Result) = 0 then
  begin
    Result := sDefaultSHXFont;
    if Length(Result) <= 0 then
      Result := 'Arial';
  end;
end;

function TsgDXFEntitySample.GetDimArrowType(const ADimProps: TsgDimStyle;
  const ANameValue: TsgDimNameVal): TsgDimArrowType;
begin
  Result := datClosedfilled;
  case ANameValue of
    vnDIMBLK1:
      Result := GetDimArrowTypeByDimSah(ADimProps.Sah, ADimProps.Arrows.Blk,
        ADimProps.Arrows.Blk1);
    vnDIMBLK2:
      Result := GetDimArrowTypeByDimSah(ADimProps.Sah, ADimProps.Arrows.Blk,
        ADimProps.Arrows.Blk2);
    vnDIMLRBLK:
      Result := ADimProps.Arrows.LrBlk;
  end;
end;

function TsgDXFEntitySample.GetDimBlk1: Byte;
begin
  Result := GetArrowByte(GetDimArrowType(GetActiveHeadVar^.DimProps,
    vnDIMBLK1));
end;

function TsgDXFEntitySample.GetDimBlk2: Byte;
begin
  Result := GetArrowByte(GetDimArrowType(GetActiveHeadVar^.DimProps,
    vnDIMBLK2));
end;

function TsgDXFEntitySample.GetDimLrBlk: Byte;
begin
  Result := GetArrowByte(GetDimArrowType(GetActiveHeadVar^.DimProps,
    vnDIMLRBLK));
end;

function TsgDXFEntitySample.GetDimExtLineExt: TsgFloat;
begin
  Result := GetActiveHeadVar^.DimProps.Exe;
end;

function TsgDXFEntitySample.GetDimExtLineOffset: TsgFloat;
begin
  Result := GetActiveHeadVar^.DimProps.Exo;
end;

function TsgDXFEntitySample.GetDimTextHeight: TsgFloat;
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  Result := GetActiveHeadVar^.DimProps.Txt;
  vDimStyle := GetDimStyle;
  if Assigned(vDimStyle) then
    vDimStyle.GetTextHeightReal(Result);
end;

function TsgDXFEntitySample.GetDimForceText: Integer;
begin
  Result := GetActiveHeadVar^.DimProps.Tix;
end;

function TsgDXFEntitySample.GetDimLFac: Double;
begin
  Result := GetActiveHeadVar^.DimProps.LFac;
end;

function TsgDXFEntitySample.GetDimPrecision: Integer;
begin
  Result := GetActiveHeadVar^.DimProps.Dec;
end;

function TsgDXFEntitySample.GetDimScale: Double;
begin
  Result := GetActiveHeadVar^.DimProps.Scale;
end;

function TsgDXFEntitySample.GetDimStyle: TsgDXFDimensionStyle;
begin
  if (FConverter <> nil) and (FConverter.FDimStyles <> nil) then
    Result := TsgDXFDimensionStyle(FConverter.FDimStyles.FindEntByName
      (FConverter.HeadVarStruct.DimStyle))
  else
    Result := nil;
end;

function TsgDXFEntitySample.GetLayer: TsgDXFLayer;
begin
  if (FConverter <> nil) and (FConverter.FLayers <> nil) then
    Result := TsgDXFLayer(FConverter.FLayers.FindEntByName
      (FConverter.FHeadVarStruct.CLayer))
  else
    Result := nil;
end;

function TsgDXFEntitySample.GetLineType: TsgDXFLineType;
begin
  if FConverter <> nil then
    Result := TsgDXFLineType
      (FConverter.LTypeByName(FConverter.FHeadVarStruct.CELType))
  else
    Result := nil;
end;

function TsgDXFEntitySample.GetLineTypeScale: Double;
begin
  Result := GetActiveHeadVar^.CELTScale;
end;

function TsgDXFEntitySample.GetLineWeight: Double;
begin
  Result := GetActiveHeadVar^.CELWeight;
end;

function TsgDXFEntitySample.GetPointDisplayMode: Integer;
begin
  Result := GetActiveHeadVar^.PointDisplayMode;
end;

function TsgDXFEntitySample.GetPointDisplaySize: Double;
begin
  Result := GetActiveHeadVar^.PointDisplaySize;
end;

function TsgDXFEntitySample.GetDimTextAlign: Integer;

  function GetTexAlign(const AHeadVar: PsgHeadVarStruct): Integer;
  begin
    if AHeadVar^.DimProps.Tih then
      Result := 0 // gorizontal - default
    else
    begin
      if AHeadVar^.DimProps.Toh then
        Result := 2 // ISO
      else
        Result := 1; // align
    end;
  end;

begin
  Result := GetTexAlign(GetActiveHeadVar);
end;

function TsgDXFEntitySample.GetDimTextColor: TsgColorCAD;
begin
  Result := GetActiveHeadVar^.DimProps.ClrT;
end;

function TsgDXFEntitySample.GetTextStyle: TsgDXFStyle;
begin
  if (FConverter <> nil) and (FConverter.FStyles <> nil) then
    Result := TsgDXFStyle(FConverter.FStyles.FindEntByName
      (FConverter.HeadVarStruct.TextStyle))
  else
    Result := nil;
end;

function TsgDXFEntitySample.GetTextRotation: TsgFloat;
begin
  Result := FTextRotation;
end;

procedure TsgDXFEntitySample.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
  if FConverter = nil then
    FBackGroundImage := nil;
end;

procedure TsgDXFEntitySample.SetArrowSize(const Value: Double);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if (FConverter <> nil) and (Value >= 0) then
  begin
    BeforeChange(prtArrowSize);
    FConverter.FHeadVarStruct.DimProps.Asz := Value;
    vDimStyle := DimStyle;
    if vDimStyle <> nil then
      vDimStyle.FDimProps.Asz := FConverter.FHeadVarStruct.DimProps.Asz;
    AfterChange(prtArrowSize);
  end;
end;

procedure TsgDXFEntitySample.SetBackGroundImage(const Value: TsgDXFImageEnt);
begin
  BeforeChange(prtBackGroundImage);
  FBackGroundImage := Value;
  AfterChange(prtBackGroundImage);
end;

procedure TsgDXFEntitySample.SetColorCAD(const Value: TsgColorCAD);
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtColor);
    FConverter.FHeadVarStruct.CEColor := Value;
    AfterChange(prtColor);
  end;
end;

procedure TsgDXFEntitySample.SetDimTextAlign(const Value: Integer);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtDimTextAlign);
    case Value of
      1: // align
        begin
          FConverter.FHeadVarStruct.DimProps.Tih := False;
          FConverter.FHeadVarStruct.DimProps.Toh := False;
        end;
      2: // ISO
        begin
          FConverter.FHeadVarStruct.DimProps.Tih := False;
          FConverter.FHeadVarStruct.DimProps.Toh := True;
        end;
    else // gorizontal - default
      FConverter.FHeadVarStruct.DimProps.Tih := True;
      FConverter.FHeadVarStruct.DimProps.Toh := True;
    end;
    vDimStyle := DimStyle;
    if vDimStyle <> nil then
    begin
      vDimStyle.FDimProps.Tih := FConverter.FHeadVarStruct.DimProps.Tih;
      vDimStyle.FDimProps.Toh := FConverter.FHeadVarStruct.DimProps.Toh;
    end;
    AfterChange(prtDimTextAlign);
  end;
end;

procedure TsgDXFEntitySample.SetDimTextColor(const Value: TsgColorCAD);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtDimTextColor);
    FConverter.FHeadVarStruct.DimProps.ClrT := Value;
    vDimStyle := DimStyle;
    if vDimStyle <> nil then
      vDimStyle.FDimProps.ClrT := FConverter.FHeadVarStruct.DimProps.ClrT;
    AfterChange(prtDimTextColor);
  end;
end;

procedure TsgDXFEntitySample.SetDimTextOffset(const Value: Double);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtDimTextOffset);
    FConverter.FHeadVarStruct.DimProps.GAP := Value;
    vDimStyle := DimStyle;
    if vDimStyle <> nil then
      vDimStyle.FDimProps.GAP := FConverter.FHeadVarStruct.DimProps.GAP;
    AfterChange(prtDimTextOffset);
  end
end;

procedure TsgDXFEntitySample.SetDimTextPosVert(const Value: TsgDimTextPosVert);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtDimTextPosVert);
    FConverter.FHeadVarStruct.DimProps.Tad := Integer(Value);
    vDimStyle := DimStyle;
    if vDimStyle <> nil then
      vDimStyle.FDimProps.Tad := FConverter.FHeadVarStruct.DimProps.Tad;
    AfterChange(prtDimTextPosVert);
  end
end;

procedure TsgDXFEntitySample.SetFilletRadius(const Value: Double);
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtFilletRadius);
    FConverter.FHeadVarStruct.FilletRadius := Value;
    AfterChange(prtFilletRadius);
  end;
end;

procedure TsgDXFEntitySample.SetFontHeight(const Value: TsgFloat);
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtTextSize);
    FConverter.FHeadVarStruct.TextSize := Abs(Value);
    AfterChange(prtTextSize);
  end;
end;

procedure TsgDXFEntitySample.SetDimArrowType(var ADimProps: TsgDimStyle;
  const ANameValue: TsgDimNameVal; const AType: TsgDimArrowType);
const
  cnstPropertyTypeArrow: array [vnDIMBLK .. vnDIMLRBLK] of TsgPropertyType =
    (prtArrowType, prtArrowType1, prtArrowType2, prtArrowTypeL);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if FConverter <> nil then
  begin
    CheckArroyType(AType);
    BeforeChange(cnstPropertyTypeArrow[ANameValue]);
    vDimStyle := DimStyle;
    case ANameValue of
      vnDIMBLK1:
        begin
          SetDimArrowType1BySah(AType, FConverter.FHeadVarStruct.DimProps);
          if vDimStyle <> nil then
            vDimStyle.DimArrowType1 := AType;
        end;
      vnDIMBLK2:
        begin
          SetDimArrowType2BySah(AType, FConverter.FHeadVarStruct.DimProps);
          if vDimStyle <> nil then
            vDimStyle.DimArrowType2 := AType;
        end;
      vnDIMLRBLK:
        begin
          ADimProps.Arrows.LrBlk := AType;
          if vDimStyle <> nil then
            vDimStyle.DIMLDRBLKT := AType;
        end;
    end;
    AfterChange(cnstPropertyTypeArrow[ANameValue]);
  end;
end;

procedure TsgDXFEntitySample.SetDimBlk1(const Value: Byte);
begin
  SetDimArrowType(FConverter.FHeadVarStruct.DimProps, vnDIMBLK1,
    GetArrowType(Value));
end;

procedure TsgDXFEntitySample.SetDimBlk2(const Value: Byte);
begin
  SetDimArrowType(FConverter.FHeadVarStruct.DimProps, vnDIMBLK2,
    GetArrowType(Value));
end;

procedure TsgDXFEntitySample.SetDimLrBlk(const Value: Byte);
begin
  SetDimArrowType(FConverter.FHeadVarStruct.DimProps, vnDIMLRBLK,
    GetArrowType(Value));
end;

procedure TsgDXFEntitySample.SetDimExtLineExt(const Value: TsgFloat);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtDimExtLineExt);
    FConverter.FHeadVarStruct.DimProps.Exe := Value;
    vDimStyle := DimStyle;
    if vDimStyle <> nil then
      vDimStyle.FDimProps.Exe := FConverter.FHeadVarStruct.DimProps.Exe;
    AfterChange(prtDimExtLineExt);
  end;
end;

procedure TsgDXFEntitySample.SetDimExtLineOffset(const Value: TsgFloat);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtDimExtLineExo);
    FConverter.FHeadVarStruct.DimProps.Exo := Value;
    vDimStyle := DimStyle;
    if vDimStyle <> nil then
      vDimStyle.FDimProps.Exo := FConverter.FHeadVarStruct.DimProps.Exo;
    AfterChange(prtDimExtLineExo);
  end;
end;

procedure TsgDXFEntitySample.SetDimTextHeight(const Value: TsgFloat);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtDimTextSize);
    FConverter.FHeadVarStruct.DimProps.Txt := Abs(Value);
    vDimStyle := DimStyle;
    if vDimStyle <> nil then
      vDimStyle.FDimProps.Txt := FConverter.FHeadVarStruct.DimProps.Txt;
    AfterChange(prtDimTextSize);
  end;
end;

procedure TsgDXFEntitySample.SetDimForceText(const Value: Integer);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtDimTextForce);
    FConverter.FHeadVarStruct.DimProps.Tix := Value;
    vDimStyle := DimStyle;
    if vDimStyle <> nil then
      vDimStyle.FDimProps.Tix := FConverter.FHeadVarStruct.DimProps.Tix;
    AfterChange(prtDimTextForce);
  end;
end;

procedure TsgDXFEntitySample.SetDimLFac(const Value: Double);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtDimMeasurementsScale);
    FConverter.FHeadVarStruct.DimProps.LFac := Value;
    vDimStyle := DimStyle;
    if vDimStyle <> nil then
      vDimStyle.FDimProps.LFac := FConverter.FHeadVarStruct.DimProps.LFac;
    AfterChange(prtDimMeasurementsScale);
  end;
end;

procedure TsgDXFEntitySample.SetDimPrecision(const Value: Integer);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtDimPrecision);
    FConverter.FHeadVarStruct.DimProps.Dec := Value;
    vDimStyle := DimStyle;
    if vDimStyle <> nil then
      vDimStyle.FDimProps.Dec := FConverter.FHeadVarStruct.DimProps.Dec;
    AfterChange(prtDimPrecision);
  end;
end;

procedure TsgDXFEntitySample.SetDimScale(const Value: Double);
var
  vDimStyle: TsgDXFDimensionStyle;
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtDimScale);
    FConverter.FHeadVarStruct.DimProps.Scale := Value;
    vDimStyle := DimStyle;
    if vDimStyle <> nil then
      vDimStyle.FDimProps.Scale := FConverter.FHeadVarStruct.DimProps.Scale;
    AfterChange(prtDimScale);
  end;
end;

procedure TsgDXFEntitySample.SetDimStyle(const Value: TsgDXFDimensionStyle);
begin
  if (Value = nil) or (FConverter = nil) then
    Exit;
  BeforeChange(prtDimStyle);
  FConverter.FHeadVarStruct.DimStyle := Value.Name;
  if DimStyle.TextStyle <> nil then
    FConverter.FHeadVarStruct.DimTextStyle := Value.TextStyle.Name
  else
    FConverter.FHeadVarStruct.DimTextStyle := cnstSGHeadVarStruct.DimTextStyle;
  FConverter.FHeadVarStruct.DimProps := Value.FDimProps;
  AfterChange(prtDimStyle);
end;

procedure TsgDXFEntitySample.SetLayer(const Value: TsgDXFLayer);
begin
  if (FConverter <> nil) and (Value <> nil) and (not Value.Frozen) then
  begin
    BeforeChange(prtLayer);
    if Value <> nil then
      FConverter.FHeadVarStruct.CLayer := Value.Name
    else
      FConverter.FHeadVarStruct.CLayer := '';
    AfterChange(prtLayer);
  end;
end;

procedure TsgDXFEntitySample.SetLineType(const AValue: TsgDXFLineType);
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtLineType);
    if AValue <> nil then
      FConverter.FHeadVarStruct.CELType := AValue.Name
    else
      FConverter.FHeadVarStruct.CELType := '';
    AfterChange(prtLineType);
  end;
end;

procedure TsgDXFEntitySample.SetLineTypeScale(Value: Double);
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtLineTypeScale);
    FConverter.FHeadVarStruct.CELTScale := Abs(Value);
    AfterChange(prtLineTypeScale);
  end;
end;

procedure TsgDXFEntitySample.SetLineWeight(Value: Double);
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtLineWeight);
    FConverter.FHeadVarStruct.CELWeight := Value;
    AfterChange(prtLineWeight);
  end;
end;

procedure TsgDXFEntitySample.SetPointDisplayMode(const Value: Integer);
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtPointDisplayMode);
    FConverter.FHeadVarStruct.PointDisplayMode := Value;
    AfterChange(prtPointDisplayMode);
  end;
end;

procedure TsgDXFEntitySample.SetPointDisplaySize(const Value: Double);
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtPointDisplaySize);
    FConverter.FHeadVarStruct.PointDisplaySize := Value;
    AfterChange(prtPointDisplaySize);
  end;
end;

procedure TsgDXFEntitySample.SetTextStyle(const Value: TsgDXFStyle);
begin
  if (Value = nil) or (FConverter = nil) then
    Exit;
  BeforeChange(prtTextStyle);
  FConverter.FHeadVarStruct.TextStyle := Value.Name;
  AfterChange(prtTextStyle);
end;

procedure TsgDXFEntitySample.SetTextRotation(const AValue: TsgFloat);
begin
  if FConverter <> nil then
  begin
    BeforeChange(prtTextRotation);
    try
      FTextRotation := AValue;
    finally
      AfterChange(prtTextRotation);
    end;
  end;
end;

function TsgDXFEntitySample.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  if IsFullPropsOrXMLHelp(AMode) or (LineTypeScale <> 1) then
    ANode.AddAttribNV(cnstXMLNames[xmlLineTypeScale].Name).ValueAsDouble :=
      LineTypeScale;
  if IsXMLHelp(AMode) then
  begin
    ANode.AddAttribNV(cnstXMLNames[xmlLayerName].Name);
  end
  else
  begin
    if Assigned(Layer) and (IsFullProps(AMode) or (Layer.Name <> '0')) then
      ANode.AddAttribNV(cnstXMLNames[xmlLayerName].Name).ValueAsStr :=
        Layer.Name;
  end;
end;

function TsgDXFEntitySample.UseTextStyleFixedHeight: Boolean;
var
  vHeight: Double;
  vDimStyle: TsgDXFDimensionStyle;
begin
  Result := False;
  vDimStyle := GetDimStyle;
  if Assigned(vDimStyle) then
    Result := not vDimStyle.GetTextHeightReal(vHeight);
end;

function TsgDXFEntitySample.GetArrowSize: Double;
begin
  Result := GetActiveHeadVar^.DimProps.Asz;
end;

{ TsgDXFPenEntity }

function TsgDXFPenEntity.IsOnePixelOptimisationValid: Boolean; // evg
begin
  Result := (Lines = nil) or Lines.IsSolid;
end;

constructor TsgDXFPenEntity.Create;
begin
  inherited Create;
  FLineTypeScale := 1;
end;

function TsgDXFPenEntity.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlLineTypeScale:
      LineTypeScale := ANode.ValueAsDouble;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFPenEntity.GetLineTypeScale: Double;
begin
  Result := FLineTypeScale;
end;

procedure TsgDXFPenEntity.SetLineTypeScale(Value: Double);
begin
  FLineTypeScale := Abs(Value);
end;

function TsgDXFPenEntity.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  if IsFullPropsOrXMLHelp(AMode) or (LineTypeScale <> 1) then
    ANode.AddAttribNV(cnstXMLNames[xmlLineTypeScale].Name).ValueAsDouble :=
      LineTypeScale;
end;

{ TsgDXFPenTableItem }

procedure TsgDXFPenTableItem.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFPenTableItem then
    FFlags := TsgDXFPenTableItem(Source).Flags;
end;

function TsgDXFPenTableItem.GetFlags: Integer;
begin
  Result := FFlags;
end;

procedure TsgDXFPenTableItem.SetFlags(const Value: Integer);
begin
  FFlags := Value;
end;

{ TsgDXFObjectEntityLineType }

procedure TsgDXFObjectEntityLineType.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFObjectEntityLineType then
    LineType := TsgDXFObjectEntityLineType(Source).LineType;
end;

procedure TsgDXFObjectEntityLineType.ClearReferences;
begin
  inherited ClearReferences;
  FLineTypeItem.Item := nil;
end;

constructor TsgDXFObjectEntityLineType.Create;
begin
  inherited Create;
  FLineTypeItem := TsgTableItem.Create;
end;

procedure TsgDXFObjectEntityLineType.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FLineTypeItem);
end;

function TsgDXFObjectEntityLineType.GetLines: TsgLines;
begin
  if (LineType = nil) or (LineType.Name = sByLayer) then
  begin
    if Layer <> nil then
      Result := Layer.Lines
    else
      Result := StdLines;
  end
  else
    Result := LineType.Lines;
end;

function TsgDXFObjectEntityLineType.GetLineType: TsgDXFLineType;
begin
  Result := TsgDXFLineType(FLineTypeItem.Item);
end;

procedure TsgDXFObjectEntityLineType.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(LineType) and (LineType.ClassType = TsgLinkObject) then
    LineType := TsgDXFLineType(TsgLinkObject(LineType)
      .GetObject(AConverter.Sections[csLTypes]));
end;

procedure TsgDXFObjectEntityLineType.LoadedInternal
  (AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
  if LineType = nil then
    LineType := AConverter.LTypeByName(sByLayer);
end;

procedure TsgDXFObjectEntityLineType.SetLineType(const AValue: TsgDXFLineType);
begin
  FLineTypeItem.Item := AValue;
end;

{ TsgDXFLineType }

procedure TsgDXFLineType.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFLineType then
    Lines.Assign(TsgDXFLineType(Source).Lines);
end;

constructor TsgDXFLineType.Create;
begin
  inherited Create;
  FLines := TsgLines.Create;
end;

procedure TsgDXFLineType.AddComplexElement(const AComplexType: Byte;
  const ADash, ARotation, AScale, AXOffset, AYOffset: Double;
  AStyle: TsgDXFStyle; const AShapeNumber: Byte; const AText: string = '';
  AScaleFactor: Double = cnstLTScale);
var
  vElement: PsgLTypeElement;
begin
  New(vElement);
  vElement^.ComplexType := AComplexType; // 74
  vElement^.Dash := ADash * AScaleFactor; // 49
  vElement^.Rotation := ARotation; // 50
  vElement^.Scale := AScale * AScaleFactor; // 46
  vElement^.XOffset := AXOffset * AScaleFactor; // 44
  vElement^.YOffset := AYOffset * AScaleFactor; // 45
  vElement^.Style := AStyle; // 340
  vElement^.Text := AText; // 9
  vElement^.ShapeNumber := AShapeNumber; // 75
  FLines.Add(vElement);
end;

procedure TsgDXFLineType.AddDashElement(const ADash: Double;
  AScaleFactor: Double = cnstLTScale);
var
  vElement: PsgLTypeElement;
begin
  New(vElement);
  FillChar(vElement^, SizeOf(vElement^), 0);
  vElement^.Dash := ADash * AScaleFactor;
  vElement^.Text := '';
  FLines.Add(vElement);
end;

procedure TsgDXFLineType.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FLines);
end;

function TsgDXFLineType.GetLines: TsgLines;
begin
  Result := FLines;
end;

procedure TsgDXFLineType.SetLineTypeScale(Value: Double);
begin
  inherited SetLineTypeScale(Value);
  if FLines <> nil then
    FLines.Scale := Abs(Value);
end;

procedure TsgDXFLineType.SetName(const AName: string);
var
  vName: string;
begin
  vName := AName;
  CheckStandartNames(vName);
  inherited SetName(vName);
end;

procedure TsgDXFLineType.Link(AConverter: TsgDXFConverter);
var
  I: Integer;
  vStyle: TObject;
begin
  inherited Link(AConverter);
  for I := 0 to Lines.ElementsCount - 1 do
  begin
    vStyle := TObject(Lines.Elements[I].Style);
    if Assigned(vStyle) and (vStyle.ClassType = TsgLinkObject) then
      vStyle := TsgLinkObject(vStyle).GetObject(AConverter.Sections[csStyles]);
    Lines.Elements[I].Style := vStyle;
  end;
end;

procedure TsgDXFLineType.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
  FLines.Loaded(AConverter);
  // "CONTINUOUS" linetype always as continuous line
  if UpperCase(Name) = sContinuous then
    FLines.Clear;
end;

{ TsgDXFLayer }

procedure TsgDXFLayer.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFLayer then
  begin
    LineType := TsgDXFLayer(Source).LineType;
    FVisible := TsgDXFLayer(Source).FVisible;
    FIsPlotting := TsgDXFLayer(Source).IsPlotting;
  end;
end;

constructor TsgDXFLayer.Create;
begin
  inherited Create;
  FLineTypeItem := TsgTableItem.Create;
  FVisible := True;
  FIsPlotting := True;
  FLineWeight := fLineWeightDefault;
  FColor := cnstColorCADByBlackWhite;
  FIsCheckName := GlobalCheckNameLayer;
end;

procedure TsgDXFLayer.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FLineTypeItem);
end;

function TsgDXFLayer.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);

  case AType.ID of
    xmlName:
      begin
        if not IsNameCorrect(Name) then
        begin
          Result := cnstXML_ERROR;
          if Assigned(AResult) then
          begin
            DoErrorXMLNode(AResult.Errors, False, ANode, xmlName);
          end;
          Exit;
        end;
      end;
  end;

  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlVisible:
      Visible := ANode.ValueAsBool;
    xmlLocked:
      Locked := ANode.ValueAsBool;
    xmlFrozen:
      Frozen := ANode.ValueAsBool;
    xmlFrozenByNewViewPort:
      IsFrozenByNewViewPort := ANode.ValueAsBool;
    xmlXrefLink:
      XrefLink := ANode.ValueAsBool;
    xmlIsPlotting:
      IsPlotting := ANode.ValueAsBool;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFLayer.GetVisible: Boolean;
begin
  Result := FVisible;
end;

function TsgDXFLayer.GetXrefLink: Boolean;
begin
  Result := FFlags and 16 <> 0;
end;

function TsgDXFLayer.GetContainerLayer: TsgDXFLayer;
var
  vLayerName, vBlockName: string;
  vMainConv: TsgDXFConverter;
begin
  Result := nil;
  if Assigned(Converter) and Assigned(Converter.FContainerXref) then
  begin
    vMainConv := Converter.GetMainConverter;
    vLayerName := Name;
    if vLayerName <> '0' then
    begin
      vBlockName := Converter.FContainerXref.Block.Name;
      vLayerName := vBlockName + cnstXRefNameDelimiter + vLayerName;
    end;
    Result := TsgDXFLayer(vMainConv.FLayers.FindEntByName(vLayerName));
  end;
end;

function TsgDXFLayer.GetFrozen: Boolean;
begin
  Result := FFlags and 1 <> 0;
end;

function TsgDXFLayer.GetFrozenByNewViewPort: Boolean;
begin
  Result := FFlags and 2 <> 0;
end;

function TsgDXFLayer.GetIsPlotting: Boolean;
begin
  Result := (AnsiUpperCase(Name) <> sLayerDefPoints) and FIsPlotting;
end;

function TsgDXFLayer.GetLines: TsgLines;
begin
  if LineType = nil then
    Result := inherited GetLines
  else
    Result := LineType.Lines;
end;

function TsgDXFLayer.GetLineType: TsgDXFLineType;
begin
  Result := TsgDXFLineType(FLineTypeItem.Item);
end;

function TsgDXFLayer.GetLineWeight: Double;
begin
  Result := FLineWeight;
end;

function TsgDXFLayer.GetLocked: Boolean;
begin
  Result := FFlags and 4 <> 0;
end;

function TsgDXFLayer.GetUsed: Boolean;
begin
  Result := FNamedItem.RefCount > 0;
end;

procedure TsgDXFLayer.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(LineType) and (LineType.ClassType = TsgLinkObject) then
    LineType := TsgDXFLineType(TsgLinkObject(LineType)
      .GetObject(AConverter.Sections[csLTypes]));
end;

procedure TsgDXFLayer.LoadedInternal(AConverter: TsgDXFConverter);
var
  vColorCAD: TsgColorCAD;
  vLTypeName: string;
begin
  inherited LoadedInternal(AConverter);
  vColorCAD := ColorCAD;
  if Integer(vColorCAD.Color) < 0 then // invisible
  begin
    vColorCAD.Color := -Integer(vColorCAD.Color);
    ColorCAD := vColorCAD;
    FVisible := False;
  end;
  if Assigned(LineType) then // layer has not line type by layer or by block
  begin
    vLTypeName := AnsiUpperCase(LineType.Name);
    if (vLTypeName = sByLayer) or (vLTypeName = sByBlock) then
      LineType := AConverter.LTypeByName(sContinuous);
  end;
  if Name = cnstAdskConstraints then
    Frozen := True;
end;

procedure TsgDXFLayer.SetFrozen(AFrozen: Boolean);
begin
  FFlags := (FFlags and not 1) or Ord(AFrozen);
end;

procedure TsgDXFLayer.SetFrozenByNewViewPort(const Value: Boolean);
begin
  FFlags := (FFlags and not 2) or (Ord(Value) shl 1);
end;

procedure TsgDXFLayer.SetLineType(const AValue: TsgDXFLineType);
begin
  FLineTypeItem.Item := AValue;
end;

procedure TsgDXFLayer.SetLineWeight(Value: Double);
begin
  FLineWeight := Value;
end;

procedure TsgDXFLayer.SetLocked(const Value: Boolean);
begin
  FFlags := (FFlags and not 4) or (Ord(Value) shl 2);
end;

procedure TsgDXFLayer.SetName(const AName: string);
begin
  if IsCheckName then
  begin
    if not IsNameCorrect(AName, [cnstVertSlash, cnstStar]) then
      raise EsgIncorrectNameLayer.Create(sIncorrectNameLayer);
  end;
  SetNameDirect(AName);
end;

procedure TsgDXFLayer.SetNameDirect(const AName: string);
begin
  inherited SetName(AName);
  if AName = cnstAdskConstraints then
    Frozen := True;
end;

procedure TsgDXFLayer.SetVisible(Value: Boolean);
begin
  FVisible := Value;
end;

procedure TsgDXFLayer.SetXrefLink(const Value: Boolean);
begin
  FFlags := (FFlags and ($FF and not $30)) or // mask = 00110000b
    (Ord(Value) shl 4) or (Ord(Value) shl 5);
  // set this bit when xref file resolved
end;

function TsgDXFLayer.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlVisible].Name).ValueAsBool := Visible;
  ANode.AddAttribNV(cnstXMLNames[xmlLocked].Name).ValueAsBool := Locked;
  ANode.AddAttribNV(cnstXMLNames[xmlFrozen].Name).ValueAsBool := Frozen;
  ANode.AddAttribNV(cnstXMLNames[xmlFrozenByNewViewPort].Name).ValueAsBool :=
    IsFrozenByNewViewPort;
  ANode.AddAttribNV(cnstXMLNames[xmlXrefLink].Name).ValueAsBool := XrefLink;
  ANode.AddAttribNV(cnstXMLNames[xmlIsPlotting].Name).ValueAsBool := IsPlotting;
end;

{ TsgDXFGroup }

procedure TsgDXFGroup.SetEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity);
begin
  FEntities[AIndex] := AEntity;
end;

procedure TsgDXFGroup.SetViewPortProperty(const AViewPort: TsgDXFViewport;
  const APaperSpaceBlock: Boolean);
begin
  Inc(FViewPortOrdIndex);
  AViewPort.FOrdIndex := FViewPortOrdIndex;
  // if APaperSpaceBlock then
  // AViewPort.FPaperSpaceBlock := TsgDXFBlock(Self);//by TgsDXFBlock
  if (FViewPortOrdIndex = 0) or not Assigned(FViewPortWithMinIndex) then
    FViewPortWithMinIndex := AViewPort;
  if AViewPort.Handle < FViewPortWithMinIndex.Handle then
  begin
    SwapInts(FViewPortWithMinIndex.FOrdIndex, AViewPort.FOrdIndex);
    FViewPortWithMinIndex := AViewPort;
  end;
end;

// function TsgDXFGroup.AddHandleItem(const AItem: TsgDXFEntity): Integer;
// begin
// Result := -1;
// if AItem.Handle <> cnstBadHandle then
// Result := FSortHandles.Add(AItem.Handle, AItem);
// end;

procedure TsgDXFGroup.ApplyBox;
var
  I: Integer;
begin
  FBox := BadRect;
  for I := 0 to Count - 1 do // FBox is union of all entities
    if Entities[I].Visibility then
      UnionFRect(FBox, Entities[I].Box);
end;

procedure TsgDXFGroup.Clear(const ADoFree: Boolean);
begin
  // FSortHandles.Clear(True);
  inherited Clear(ADoFree);
  if InternalFlags and 2 = 0 then
    ClearEntCollection(FEntities, ADoFree)
  else
    ClearItemsCollection(FEntities, ADoFree);
end;

procedure TsgDXFGroup.AddEntities(const ASource: TsgDXFEntity;
  AConverter: TsgDXFConverter = nil);
var
  I: Integer;
  vEntNew, vEntSource: TsgDXFEntity;
begin
  if not Assigned(AConverter) then
    AConverter := Converter;
  for I := 0 to ASource.Count - 1 do
  begin
    vEntSource := TsgDXFEntity(ASource.Entities[I]);
    vEntNew := TsgDXFEntityClass(vEntSource.ClassType).Create;
    vEntNew.AssignEntity(vEntSource);
    AddEntity(vEntNew);
    if Assigned(AConverter) then
      AConverter.Loads(vEntNew);
  end;
end;

constructor TsgDXFGroup.Create;
begin
  inherited Create;
  FEntities := TListNotify(TListNotify.CreateList(ListNotify));
  FBox := BadRect;
  FViewPortOrdIndex := -1;
  // FSortHandles := TsgCollection.Create;
  // FSortHandles.Duplicates := dupIgnore;
  // FSortHandles.Sorted := True;
end;

function TsgDXFGroup.DeleteEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := FEntities[AIndex];
  FEntities.Delete(AIndex);
end;

// function TsgDXFGroup.DeleteHandleItem(const AItem: TsgDXFEntity): Integer;
// begin
// Result := FSortHandles.IndexOf(AItem.Handle);
// if Result >= 0 then
// FSortHandles.Delete(Result);
// end;

procedure TsgDXFGroup.ExchangeEntity(AIndex1, AIndex2: Integer);
begin
  if AIndex1 <> AIndex2 then
    FEntities.Exchange(AIndex1, AIndex2);
end;

procedure TsgDXFGroup.FreeReferences;
begin
  inherited FreeReferences;
  // FreeAndNil(FSortHandles);
  FreeAndNil(FEntities);
end;

function TsgDXFGroup.IndexOfEntity(const AEntity: TsgDXFEntity): Integer;
begin
  Result := FEntities.IndexOf(AEntity);
end;

function TsgDXFGroup.IndexOfName(const AName: string): Integer;
begin
  if not FindChildByEntName(Self, AName, False, Result) then
    Result := -1;
end;

function TsgDXFGroup.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  Result := AEntity.EntType <> ceSeqEnd;
  if Result then
    FEntities.Insert(AIndex, AEntity);
end;

procedure TsgDXFGroup.Iterate(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
var
  I: Integer;
begin
  for I := 0 to Count - 1 do
    Entities[I].Invoke(AConverter, Proc, FinishProc);
end;

function TsgDXFGroup.GetBox: TFRect;
begin
  Result := FBox;
end;

function TsgDXFGroup.GetCount: Integer;
begin
  Result := FEntities.Count;
end;

procedure TsgDXFGroup.SortEntByHandle;
begin
  QSortList(FEntities, CompareHandleEntities);
end;

function TsgDXFGroup.GetEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := TsgDXFEntity(FEntities[AIndex]);
end;

{$IFDEF SGDEL_2005}

function TsgDXFGroup.GetEnumerator: TListEnumerator;
begin
  Result := FEntities.GetEnumerator;
end;
{$ENDIF}

function TsgDXFGroup.GetStrValue: string;
begin
  Result := EntName;
end;

procedure TsgDXFGroup.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
  ApplyBox;
end;

{ TsgDXFGroupName }

procedure TsgDXFGroupName.SetName(const AName: string);
begin
  FNamedItem.Name := AName;
end;

procedure TsgDXFGroupName.SetOnListNotify(const Value: TsgObjProcListNotify);
begin
  FOnListNotify := Value
end;

procedure TsgDXFGroupName.SetOwner(const Value: TsgDXFEntity);
begin
  FNamedItem.Owner := Value;
end;

function TsgDXFGroupName.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlName].Name).Value := Name;
end;

procedure TsgDXFGroupName.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFGroupName then
    Name := Source.Name;
end;

constructor TsgDXFGroupName.Create;
begin
  inherited Create;
  FNamedItem := TsgNamedItem.Create(Self);
end;

procedure TsgDXFGroupName.DoListNotify(Ptr: Pointer; Action: TListNotification);
begin
  if Assigned(FOnListNotify) then
    FOnListNotify(Ptr, Action);
end;

function TsgDXFGroupName.EntName: string;
begin
  Result := FNamedItem.Name;
  if Result = '' then
    Result := inherited EntName;
end;

procedure TsgDXFGroupName.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FNamedItem);
end;

function TsgDXFGroupName.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlName:
      Name := ANode.ValueAsStr;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFGroupName.GetName: string;
begin
  Result := FNamedItem.Name;
end;

function TsgDXFGroupName.GetNamedItem: TObject;
begin
  Result := FNamedItem;
end;

function TsgDXFGroupName.GetOnListNotify: TsgObjProcListNotify;
begin
  Result := FOnListNotify;
end;

function TsgDXFGroupName.GetOwner: TsgDXFEntity;
begin
  Result := FNamedItem.Owner;
end;

procedure TsgDXFGroupName.ListNotify(Ptr: Pointer; Action: TListNotification);
begin
  case Action of
    lnAdded:
      begin
        inherited ListNotify(Ptr, Action);
        TsgDXFEntity(Ptr).SetOwner(Self);
        DoListNotify(Ptr, Action);
      end;
    lnExtracted, lnDeleted:
      begin
        DoListNotify(Ptr, Action);
        TsgDXFEntity(Ptr).SetOwner(nil);
        inherited ListNotify(Ptr, Action);
      end;
  end;
end;

{ TsgDXFPenLine }

function TsgDXFPenLine.GetBox: TFRect;
begin
  Result.TopLeft := Point;
  Result.BottomRight := Point;
end;

procedure TsgDXFPenLine.AddThickness(var R: TFRect);
var
  T: Double;
begin
  if FLineWeight <= 0 then
    Exit;
  T := FLineWeight / 2;
  R.Left := R.Left - T;
  R.Top := R.Top + T;
  R.Right := R.Right + T;
  R.Bottom := R.Bottom - T;
end;

procedure TsgDXFPenLine.ApplyExtrusionByPoint;
begin
  if IsExtruded then
    DoExtrusion(FPoint, FExtrusion^);
end;

function TsgDXFPenLine.IsExtruded: Boolean;
begin
  Result := FExtrusion <> nil;
end;

function TsgDXFPenLine.GetExtrusion: TFPoint;
begin
  if IsExtruded then
    Result := FExtrusion^
  else
    Result := cnstExtrusion;
end;

function TsgDXFPenLine.GetLineWeight: Double;
begin
  Result := FLineWeight;
end;

function TsgDXFPenLine.GetThickness: Double;
begin
  Result := FLineWeight;
end;

function TsgDXFPenLine.GetZThick: Double;
begin
  Result := FZThick;
end;

procedure TsgDXFPenLine.SetLineWeight(Value: Double);
begin
  FLineWeight := Value;
end;

procedure TsgDXFPenLine.SetZThick(const Value: Double);
begin
  FZThick := Value;
end;

function TsgDXFPenLine.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  if IsFullPropsOrXMLHelp(AMode) or (FZThick <> 0) then
    ANode.AddAttribNV(cnstXMLNames[xmlZThick].Name).ValueAsDouble := FZThick;
  if IsFullPropsOrXMLHelp(AMode) or IsExtruded then
    ANode.AddAttribNV(cnstXMLNames[xmlExtrusion].Name).ValueAsFPoint :=
      Extrusion;
end;

procedure TsgDXFPenLine.FreeReferences;
begin
  inherited FreeReferences;
  DisposeAndNil(FExtrusion);
end;

function TsgDXFPenLine.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlZThick:
      FZThick := ANode.ValueAsDouble;
    xmlExtrusion:
      Extrusion := ANode.ValueAsFPoint;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure TsgDXFPenLine.SetLWeight(Value: Integer);
begin
  if FLineWeight = fLineWeightByLayer then
    FLineWeight := Value / 100;
end;

procedure TsgDXFPenLine.AssignEntity(Source: TsgDXFEntity);
var
  vPenLine: TsgDXFPenLine absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFPenLine then
  begin
    FZThick := vPenLine.FZThick;
    if vPenLine.FExtrusion <> nil then
      Extrusion := vPenLine.FExtrusion^
    else
      DisposeAndNil(FExtrusion);
  end;
end;

procedure TsgDXFPenLine.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
  ApplyExtrusionByPoint;
end;

procedure TsgDXFPenLine.SetExtrusion(const Value: TFPoint);
begin
  if IsEqualFPoints(Value, cnstExtrusion) then
    DisposeAndNil(FExtrusion)
  else
  begin
    if FExtrusion = nil then
      New(FExtrusion);
    FExtrusion^ := Value;
  end;
end;

{ TsgDXFSection }

procedure TsgDXFSection.ChangeHandle(AConverter: TsgDXFConverter);
begin
  // don't set Handle for SECTIONs
end;

function TsgDXFSection.IsTablesBelongSection(ATable: TConvSection): Boolean;
begin
  Result := False;
end;

procedure TsgDXFSection.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
  if Name = cnstSectionHEADER then
    AConverter.FHeadEnd := SrcEnd;
end;

{ TsgDXFVertex }

function TsgDXFVertex.CanHaveHandle: Boolean;
begin
  Result := False; // does not have a converter
end;

procedure TsgDXFVertex.FreeReferences;
begin
  inherited FreeReferences;
  DisposeAndNil(FPolyFaceIndexes);
end;

function TsgDXFVertex.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlPoint:
      FPoint := ANode.ValueAsFPoint;
    xmlBulge:
      Bulge := ANode.ValueAsDouble;
    xmlStartWidth:
      StartWidth := ANode.ValueAsDouble;
    xmlEndWidth:
      EndWidth := ANode.ValueAsDouble;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure TsgDXFVertex.AssignEntity(Source: TsgDXFEntity);
var
  vVertex: TsgDXFVertex absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFVertex then
  begin
    FPoint := vVertex.FPoint;
    if (FPolyFaceIndexes <> nil) then
    begin
      Dispose(FPolyFaceIndexes);
      FPolyFaceIndexes := nil;
    end;
    if vVertex.FPolyFaceIndexes <> nil then
    begin
      New(FPolyFaceIndexes);
      FPolyFaceIndexes^ := vVertex.FPolyFaceIndexes^;
    end;
    FBulge := vVertex.FBulge;
    FEndWidth := vVertex.FEndWidth;
    FFlags := vVertex.FFlags;
    FStartWidth := vVertex.FStartWidth;
  end;
end;

procedure TsgDXFCustomVertex.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFCustomVertex then
    FPoint := TsgDXFCustomVertex(Source).Point
end;

function TsgDXFCustomVertex.CanDraw: Boolean;
begin
  Result := True;
end;

function TsgDXFCustomVertex.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlPoint:
      FPoint := ANode.ValueAsFPoint;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFCustomVertex.GetBox: TFRect;
begin
  Result.TopLeft := Point;
  Result.BottomRight := Point;
end;

function TsgDXFCustomVertex.GetPoint: TFPoint;
begin
  Result := FPoint;
end;

procedure TsgDXFCustomVertex.SetPoint(AValue: TFPoint);
begin
  FPoint := AValue;
end;

function TsgDXFCustomVertex.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlPoint].Name).ValueAsFPoint := FPoint;
end;

function TsgDXFVertex.GetBox: TFRect;
begin
  Result.TopLeft := Point;
  Result.BottomRight := Point;
end;

function TsgDXFVertex.GetBulge: Double;
begin
  Result := FBulge;
end;

function TsgDXFVertex.GetEndWidth: Double;
begin
  Result := FEndWidth;
end;

function TsgDXFVertex.GetFlags: Integer;
begin
  Result := FFlags;
end;

function TsgDXFVertex.GetHandle: UInt64;
begin
  Result := FHandle;
end;

function TsgDXFVertex.GetInternalFlags: Byte;
begin
  Result := 1;
end;

function TsgDXFVertex.GetIs3DVertex: Boolean;
begin
  Result := not(FFlags and 32 = 0);
end;

function TsgDXFVertex.GetPolyFaceIndex1: Integer;
begin
  if FPolyFaceIndexes = nil then
    Result := 0
  else
    Result := FPolyFaceIndexes^[1];
end;

function TsgDXFVertex.GetPolyFaceIndex2: Integer;
begin
  if FPolyFaceIndexes = nil then
    Result := 0
  else
    Result := FPolyFaceIndexes^[2];
end;

function TsgDXFVertex.GetPolyFaceIndex3: Integer;
begin
  if FPolyFaceIndexes = nil then
    Result := 0
  else
    Result := FPolyFaceIndexes^[3];
end;

function TsgDXFVertex.GetPolyFaceIndex4: Integer;
begin
  if FPolyFaceIndexes = nil then
    Result := 0
  else
    Result := FPolyFaceIndexes^[4];
end;

function TsgDXFVertex.GetStartWidth: Double;
begin
  Result := FStartWidth;
end;

function TsgDXFVertex.HasBulge: Boolean;
begin
  Result := FBulge <> 0;
end;

function TsgDXFVertex.IsPolyfaceMeshVertex: Boolean;
begin
  // Vertex is polyface mesh vertex
  Result := FFlags = 128;
end;

function TsgDXFVertex.IsSplineFrameControlPoint: Boolean;
begin
  // Vertex is spline frame control point
  Result := (FFlags and 16) <> 0;
end;

procedure TsgDXFVertex.NewPolyFaceIndexes;
begin
  if FPolyFaceIndexes = nil then
  begin
    New(FPolyFaceIndexes);
    FillChar(FPolyFaceIndexes^, SizeOf(TsgPolyFaceVertexIndexes), 0);
  end;
end;

procedure TsgDXFVertex.SetPolyFaceIndex1(const Value: Integer);
begin
  NewPolyFaceIndexes;
  FPolyFaceIndexes^[1] := Value;
end;

procedure TsgDXFVertex.SetPolyFaceIndex2(const Value: Integer);
begin
  NewPolyFaceIndexes;
  FPolyFaceIndexes^[2] := Value;
end;

procedure TsgDXFVertex.SetPolyFaceIndex3(const Value: Integer);
begin
  NewPolyFaceIndexes;
  FPolyFaceIndexes^[3] := Value;
end;

procedure TsgDXFVertex.SetPolyFaceIndex4(const Value: Integer);
begin
  NewPolyFaceIndexes;
  FPolyFaceIndexes^[4] := Value;
end;

procedure TsgDXFVertex.SetStartWidth(const Value: Double);
begin
  if not Is3DVertex then
    FStartWidth := Value;
end;

function TsgDXFVertex.GetPolyFaceIndex(Index: Integer): Integer;
begin
  if FPolyFaceIndexes = nil then
    Result := -1
  else
    Result := FPolyFaceIndexes^[Index];
end;

procedure TsgDXFVertex.SetPolyFaceIndex(Index: Integer; const Value: Integer);
begin
  if (Index <= High(TsgPolyFaceVertexIndexes)) and
    (Index >= Low(TsgPolyFaceVertexIndexes)) then
  begin
    NewPolyFaceIndexes;
    FPolyFaceIndexes^[Index] := Value;
  end;
end;

function TsgDXFVertex.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.RemoveAttributeByName(cnstXMLNames[xmlLineWeight].Name);
  ANode.AddAttribNV(cnstXMLNames[xmlPoint].Name).ValueAsFPoint := FPoint;
  if IsFullPropsOrXMLHelp(AMode) or (FBulge <> 0) then
    ANode.AddAttribNV(cnstXMLNames[xmlBulge].Name).ValueAsDouble := FBulge;
  if IsFullPropsOrXMLHelp(AMode) or (FStartWidth <> 0) or (FEndWidth <> 0) then
  begin
    ANode.AddAttribNV(cnstXMLNames[xmlStartWidth].Name).ValueAsDouble :=
      FStartWidth;
    ANode.AddAttribNV(cnstXMLNames[xmlEndWidth].Name).ValueAsDouble :=
      FEndWidth;
  end;
end;

function TsgDXFVertex.GetPoint: TFPoint;
begin
  Result := FPoint;
end;

procedure TsgDXFVertex.SetBulge(const Value: Double);
begin
  if not Is3DVertex then
    FBulge := Value;
end;

procedure TsgDXFVertex.SetEndWidth(const Value: Double);
begin
  if not Is3DVertex then
    FEndWidth := Value;
end;

procedure TsgDXFVertex.SetFlags(const Value: Integer);
begin
  FFlags := Value;
end;

procedure TsgDXFVertex.SetHandle(const AValue: UInt64);
begin
{$IFDEF SG_MODULE_LOG}
  inherited SetHandle(AValue);
{$ENDIF}
  FHandle := AValue;
end;

procedure TsgDXFVertex.SetIs3DVertex(const Value: Boolean);
begin
  FFlags := (FFlags and $DF) or (Byte(Value) shl 5);
  if Value then
  begin
    FBulge := 0;
    FEndWidth := 0;
    FStartWidth := 0;
  end;
end;

procedure TsgDXFVertex.SetPoint(const AValue: TFPoint);
begin
  FPoint := AValue;
end;

{ TsgDXFLine }

procedure TsgDXFLine.ApplyExtrusionByPoint;
begin
end;

function TsgDXFLine.GetAngle: TsgFloat;
begin
  Result := GetAngleByPoints(FPoint, FPoint1, False);
end;

function TsgDXFLine.GetBox: TFRect;
begin
  Result := inherited GetBox;
  ExpandFRect(Result, Point1);
  AddZThick(Result);
  // AddThickness(Result);
end;

function TsgDXFLine.GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean;
begin
  if FZThick = 0 then
  begin
    Proc(Point);
    Proc(Point1);
    Result := True;
  end
  else
    Result := inherited GetBoxPoints(Proc, Full);
end;

procedure TsgDXFLine.LoadedInternal(AConverter: TsgDXFConverter);
begin
  if Layer = nil then
    Layer := AConverter.LayerByName('0');
{$IFNDEF EVG} vLTScale := Lines.Scale;
  Lines.Scale := vLTScale * AConverter.LTScale * FLineTypeScale;
  try
    if Lines.IsSolid then
      GetSinglePts([FPoint, FPoint1], FDottedSingPts)
    else
    begin
      ClearRecordList(FDottedSingPts);
      Lines.Line(FPoint, FPoint1, FDottedSingPts);
    end;
  finally
    Lines.Scale := vLTScale;
  end; {$ENDIF}
end;

constructor TsgDXFLine.Create;
begin
  inherited Create;
  // FDottedSingPts := TList.Create;
end;

destructor TsgDXFLine.Destroy;
begin
  { if Assigned(FDottedSingPts) then
    begin
    for I := 0 to FDottedSingPts.Count - 1 do
    Dispose(FDottedSingPts[I]);
    FDottedSingPts.Free;
    end; }
  inherited Destroy;
end;

procedure TsgDXFLine.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFLine then
    FPoint1 := TsgDXFLine(Source).FPoint1;
end;

procedure TsgDXFLine.AddZThick(var R: TFRect);
begin
  if FZThick = 0 then
    Exit;
  ExpandFRect(R, MakeFPoint(Point.X, Point.Y, Point.Z + FZThick));
  ExpandFRect(R, MakeFPoint(Point1.X, Point1.Y, Point1.Z + FZThick));
end;

function TsgDXFLine.GetEntType: TsgCADEntities;
begin
  Result := ceLine;
end;

function TsgDXFLine.GetLength: TsgFloat;
begin
  Result := DistanceFPoint(FPoint, FPoint1);
end;

function TsgDXFLine.GetPoint1: TFPoint;
begin
  Result := FPoint1;
end;

procedure TsgDXFLine.SetAngle(const Value: TsgFloat);
var
  vDistance, vValue: Double;
  S, C: Extended;
begin
  if sgModAngle(Value, vValue) then
  begin
    vDistance := DistanceFPoint2D(FPoint, FPoint1);
    if vDistance > fAccuracy then
    begin
      SinCos(vValue * fPiDividedBy180, S, C);
      FPoint1.X := FPoint.X + C * vDistance;
      FPoint1.Y := FPoint.Y + S * vDistance;
    end;
  end;
end;

procedure TsgDXFLine.SetLength(const Value: TsgFloat);
var
  vDelta: TFPoint;
  vDistance: Double;
begin
  if IsEqualFPoints(FPoint, FPoint1) then
    Exit;
  if IsEqual(Value, 0) then
    FPoint1 := FPoint
  else
  begin
    vDistance := DistanceFPointSqr(FPoint1, FPoint);
    if vDistance > fAccuracy then
    begin
      vDistance := Sqrt(vDistance);
      vDelta := SubFPoint(FPoint1, FPoint);
      FPoint1.X := FPoint.X + Value * vDelta.X / vDistance;
      FPoint1.Y := FPoint.Y + Value * vDelta.Y / vDistance;
      FPoint1.Z := FPoint.Z + Value * vDelta.Z / vDistance;
    end
    else
      FPoint1 := FPoint;
  end;
end;

procedure TsgDXFLine.SetPoint1(AValue: TFPoint);
begin
  FPoint1 := AValue;
end;

function TsgDXFLine.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlPoint1].Name).ValueAsFPoint := Point1;
  ANode.AddAttribNV(cnstXMLNames[xmlLength].Name).ValueAsDouble := Length;
  if IsFullPropsOrXMLHelp(AMode) or (Angle <> 0) then
    ANode.AddAttribNV(cnstXMLNames[xmlAngle].Name).ValueAsDouble := Angle;
end;

function TsgDXFLine.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlPoint1:
      Point1 := ANode.ValueAsFPoint;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

{ TsgDXFPoint }

constructor TsgDXFPoint.Create;
begin
  inherited Create;
end;

procedure TsgDXFPoint.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FPoints);
end;

procedure TsgDXFPoint.AssignEntity(Source: TsgDXFEntity);
var
  vPoint: TsgDXFPoint absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFPoint then
  begin
    FPoint := vPoint.Point;
    if FPoints <> nil then
    begin
      ClearPoints;
      FPoints.Free;
      FPoints := nil;
    end;
  end;
end;

procedure TsgDXFPoint.ClearPoints;
var
  I, J, Cnt: Integer;
begin
  if FPoints <> nil then
  begin
    Dispose(FPoints[0]);
    Dispose(FPoints[1]);
    I := 2;
    while I < FPoints.Count do
    begin
      Cnt := Integer(FPoints[I]);
      Inc(I);
      J := I;
      Inc(I, Cnt);
      while J < I do
      begin
        Dispose(FPoints[J]);
        Inc(J);
      end;
    end;
    FPoints.Count := 0;
  end;
end;

procedure TsgDXFPoint.ApplyExtrusionByPoint;
begin
end;

procedure TsgDXFPoint.ClearReferences;
begin
  inherited ClearReferences;
  ClearPoints;
end;

function TsgDXFPoint.GetBox: TFRect;
begin
  if FPoints = nil then
  begin
    Result := inherited GetBox;
    ExpandFRect(Result, MakeFPoint(FPoint.X, FPoint.Y, FPoint.Z + FZThick));
  end
  else
  begin
    Result := cnstBadRect;
    Result.TopLeft := PFPoint(FPoints[0])^;
    Result.BottomRight := PFPoint(FPoints[1])^;
  end;
end;

function TsgDXFPoint.GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean;
var
  vPt: TFPoint;
begin
  if FPoints = nil then
  begin
    vPt := MakeFPoint(0, 0, FZThick);
    if Extruded(Extrusion) then
      DoExtrusion(vPt, FExtrusion^);
    vPt.X := vPt.X + FPoint.X;
    vPt.Y := vPt.Y + FPoint.Y;
    vPt.Z := vPt.Z + FPoint.Z;
    Proc(FPoint);
    Proc(vPt);
  end
  else
  begin
    Proc(PFPoint(FPoints[0])^);
    Proc(PFPoint(FPoints[1])^);
  end;
  Result := True;
end;

function TsgDXFPoint.GetEntType: TsgCADEntities;
begin
  Result := cePoint;
end;

procedure TsgDXFPoint.LoadedInternal(AConverter: TsgDXFConverter);
const
  cnstPi: Double = 3.1415926535897932384626433832795;
  cnst1DivSqrt2: Double = 1 / 1.4142135623730950488016887242097;
var
  vPDMode: Byte;
  vPDSize: Double;
  vBox: TFRect;
  vHasExtrusion: Boolean;
  P: PFPoint;

  procedure AddPt(const AX, AY, AZ: Double);
  begin
    New(P);
    FPoints.Add(P);
    P^.X := AX;
    P^.Y := AY;
    P^.Z := AZ;
    if vHasExtrusion then
      DoExtrusion(P^, FExtrusion^);
    P^.X := P^.X + FPoint.X;
    P^.Y := P^.Y + FPoint.Y;
    P^.Z := P^.Z + FPoint.Z;
    ExpandFRect(vBox, P^);
  end;

  procedure AddCircle;
  var
    I, Cnt: Integer;
    S, C: Extended;
    vStart, vDelta, vRadius: Double;
  begin
    vRadius := vPDSize * 0.5;
    Cnt := AConverter.NumberOfPartsInCircle;
    if Cnt = 0 then
      Cnt := GetNumberOfCircleParts;
    vStart := 0;
    vDelta := cnstPi * 2 / Cnt;
    FPoints.Add(Pointer(Cnt + 1));
    for I := 0 to Cnt do
    begin
      SinCos(vStart, S, C);
      AddPt(vRadius * C, vRadius * S, 0);
      vStart := vStart + vDelta;
    end;
  end;

  procedure AddCross;
  begin
    FPoints.Add(Pointer(2));
    AddPt(0, vPDSize, 0);
    AddPt(0, -vPDSize, 0);
    FPoints.Add(Pointer(2));
    AddPt(vPDSize, 0, 0);
    AddPt(-vPDSize, 0, 0);
  end;

  procedure AddCrossDiagonal;
  var
    vSize: Double;
  begin
    vSize := vPDSize * cnst1DivSqrt2;
    FPoints.Add(Pointer(2));
    AddPt(vSize, vSize, 0);
    AddPt(-vSize, -vSize, 0);
    FPoints.Add(Pointer(2));
    AddPt(vSize, -vSize, 0);
    AddPt(-vSize, vSize, 0);
  end;

  procedure AddLine;
  begin
    FPoints.Add(Pointer(2));
    New(P);
    FPoints.Add(P);
    P^ := FPoint;
    ExpandFRect(vBox, P^);
    AddPt(0, vPDSize * 0.5, 0);
  end;

  procedure AddPoint;
  begin
    FPoints.Add(Pointer(1));
    New(P);
    FPoints.Add(P);
    P^ := FPoint;
    ExpandFRect(vBox, P^);
  end;

  procedure AddSquare;
  var
    vSize: Double;
  begin
    vSize := vPDSize * 0.5;
    FPoints.Add(Pointer(5));
    AddPt(-vSize, vSize, 0);
    AddPt(vSize, vSize, 0);
    AddPt(vSize, -vSize, 0);
    AddPt(-vSize, -vSize, 0);
    AddPt(-vSize, vSize, 0);
  end;

  procedure DoZTick;
  var
    vPzTick: TFPoint;
    I, J, vCount, Cnt: Integer;
    P0: PFPoint;
  begin
    vPzTick := MakeFPoint(0, 0, FZThick);
    if vHasExtrusion then
      DoExtrusion(vPzTick, Extrusion);
    I := 2;
    vCount := FPoints.Count;
    while I < vCount do
    begin
      Cnt := Integer(FPoints[I]);
      Inc(I);
      J := I;
      Inc(I, Cnt);
      FPoints.Add(Pointer(Cnt));
      while J < I do
      begin
        P0 := FPoints[J];
        Inc(J);
        New(P);
        FPoints.Add(P);
        P^.X := P0^.X + vPzTick.X;
        P^.Y := P0^.Y + vPzTick.Y;
        P^.Z := P0^.Z + vPzTick.Z;
        ExpandFRect(vBox, P^);
      end;
    end;
  end;

begin
  inherited LoadedInternal(AConverter);
  vPDMode := Byte(AConverter.HeadVarStruct.PointDisplayMode);
  vPDSize := AConverter.HeadVarStruct.PointDisplaySize;
  if (Layer <> nil) and (Layer.Name = sLayerDefPoints) then
    vPDMode := 0;
  if Abs(vPDSize) < fAccuracy then
    vPDSize := 1;
  if vPDMode > 1 then
  begin
    vHasExtrusion := IsExtruded;
    vBox := cnstBadRect;
    if FPoints = nil then
      FPoints := TList.Create
    else
      ClearPoints;
    New(P);
    FPoints.Add(P);
    New(P);
    FPoints.Add(P);
    case vPDMode and 7 of
      0:
        AddPoint;
      2:
        AddCross;
      3:
        AddCrossDiagonal;
      4:
        AddLine;
    end;
    if (vPDMode and 32) <> 0 then
      AddCircle;
    if (vPDMode and 64) <> 0 then
      AddSquare;
    if Abs(FZThick) > fAccuracy then
      DoZTick;
    PFPoint(FPoints[0])^ := vBox.TopLeft;
    PFPoint(FPoints[1])^ := vBox.BottomRight;
  end
  else
  begin
    if FPoints <> nil then
    begin
      ClearPoints;
      FPoints.Free;
      FPoints := nil;
    end;
  end;
end;

procedure TsgDXFPoint.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
var
  vPDMode: Integer;
begin
  if (AConverter.Params.Insert <> nil) and
    (AConverter.Params.Insert.EntType = ceDimension) then
  begin
    vPDMode := AConverter.FHeadVarStruct.PointDisplayMode;
    try
      AConverter.FHeadVarStruct.PointDisplayMode := 1;
      LoadedInternal(AConverter);
    finally
      AConverter.FHeadVarStruct.PointDisplayMode := vPDMode;
    end;
  end;
  inherited Invoke(AConverter, Proc, FinishProc);
end;

{ TsgDXFSolid }

function TsgDXFSolid.GetBox: TFRect;
var
  I: Integer;
  vPts: TsgPoints4;
  vCount: Integer;
begin
  vCount := GetPoints(vPts, False, IsExtruded);
  Result.TopLeft := vPts[0];
  Result.BottomRight := Result.TopLeft;
  for I := 1 to vCount - 1 do
    ExpandFRect(Result, vPts[I]);
  if Abs(FZThick) > 0 then
  begin
    GetPoints(vPts, True, IsExtruded);
    for I := 0 to vCount - 1 do
      ExpandFRect(Result, vPts[I]);
  end;
end;

function TsgDXFSolid.GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean;
var
  R: TFRect;
  E: PFPoint;
begin
  Result := True;
  E := FExtrusion;
  FExtrusion := nil;
  R := GetBox;
  FExtrusion := E;
  if IsBadRect(R) then
    Exit;
  Proc(R.TopLeft);
  Proc(R.BottomRight);
  if not Full then
    Exit;
  Proc(MakeFPoint(R.Left, R.Top, R.Z2));
  Proc(MakeFPoint(R.Left, R.Bottom, R.Z1));
  Proc(MakeFPoint(R.Left, R.Bottom, R.Z2));
  Proc(MakeFPoint(R.Right, R.Top, R.Z1));
  Proc(MakeFPoint(R.Right, R.Top, R.Z2));
  Proc(MakeFPoint(R.Right, R.Bottom, R.Z1));
end;

procedure TsgDXFSolid.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFSolid then
  begin
    FPoint2 := TsgDXFSolid(Source).FPoint2;
    FPoint3 := TsgDXFSolid(Source).FPoint3;
    DisposeAndNil(FMatrix);
  end;
end;

function TsgDXFSolid.GetEntType: TsgCADEntities;
begin
  Result := ceSolid;
end;

function TsgDXFSolid.GetMatrix: TFMatrix;
begin
  if Assigned(FMatrix) then
    Result := FMatrix^
  else
  begin
    if IsExtruded then
    begin
      New(FMatrix);
      FMatrix^ := ExtrusionToMatrix(Extrusion);
      Result := FMatrix^;
    end
    else
      Result := cnstIdentityMat;
  end;
end;

function TsgDXFSolid.GetPoint2: TFPoint;
begin
  Result := FPoint2;
end;

function TsgDXFSolid.GetPoint3: TFPoint;
begin
  Result := FPoint3;
end;

function TsgDXFSolid.GetPoints(var APoints4: TsgPoints4;
  const AAddZThick: Boolean = False; const AExtruding: Boolean = False)
  : Integer;
var
  I: Integer;
begin
  Result := 4;

  APoints4[0] := FPoint;
  APoints4[1] := FPoint1;
  APoints4[2] := FPoint2;
  APoints4[3] := FPoint3;

  if IsEqualFPoints(APoints4[1], APoints4[2]) then
  begin
    SwapFPoints(APoints4[2], APoints4[3]);
    Dec(Result);
  end;
  if IsEqualFPoints(APoints4[0], APoints4[3]) then
    Dec(Result);
  if IsEqualFPoints(APoints4[0], APoints4[2]) then
  begin
    SwapFPoints(APoints4[2], APoints4[3]);
    Dec(Result);
  end;
  if AAddZThick and (Abs(FZThick) > 0) then
    for I := 0 to 3 do
      APoints4[I].Z := APoints4[I].Z + FZThick;
  if AExtruding and IsExtruded then
    for I := 0 to 3 do
      APoints4[I] := AffineTransformPoint(APoints4[I], GetMatrix);
end;

procedure TsgDXFSolid.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
var
  vMatrix: TFMatrix;
begin
  if IsInvoke(AConverter) then
  begin
    if IsExtruded then
    begin
      vMatrix := AConverter.Params^.Matrix;
      AConverter.Params^.Matrix :=
        FMatXMat(GetMatrix, AConverter.Params^.Matrix);
    end;
    Proc(Self);
    if IsExtruded then
    begin
      AConverter.Params^.Matrix := vMatrix;
    end;
  end;
end;

procedure TsgDXFSolid.LoadedInternal(AConverter: TsgDXFConverter);
begin
  CalcState;
end;

procedure TsgDXFSolid.SetExtrusion(const Value: TFPoint);
begin
  inherited SetExtrusion(Value);
  DisposeAndNil(FMatrix);
end;

procedure TsgDXFSolid.SetPoint2(AValue: TFPoint);
begin
  FPoint2 := AValue;
end;

procedure TsgDXFSolid.SetPoint3(AValue: TFPoint);
begin
  FPoint3 := AValue;
end;

function TsgDXFSolid.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlPoint2].Name).ValueAsFPoint := Point2;
  ANode.AddAttribNV(cnstXMLNames[xmlPoint3].Name).ValueAsFPoint := Point3;
end;

procedure TsgDXFSolid.CalcState;
var
  vPts: TsgPoints4;
  vNormal1, vNormal2: TFPoint;
  vLen1, vLen2: Double;

  function CalcNormal(const AP1, AP2, AP3: TFPoint; var ALen: Double): TFPoint;
  var
    V1, V2: TFPoint;
  begin
    V1 := SubFPoint(AP2, AP1);
    V2 := SubFPoint(AP3, AP1);
    Result := sgFunction.Vector(V1, V2);
    ALen := DistanceFVector(Result);
  end;

begin
  GetPoints(vPts);
  vNormal1 := CalcNormal(vPts[0], vPts[1], vPts[2], vLen1);
  vNormal2 := CalcNormal(vPts[0], vPts[2], vPts[3], vLen2);
  FInternalFlags := FInternalFlags and $02;
  if IsZero(vLen1) then
    FInternalFlags := FInternalFlags or $40
  else if Abs(ArcCos(-vNormal1.Z / vLen1)) < cnstPiDiv2 then
    FInternalFlags := FInternalFlags or $10;
  if IsZero(vLen2) then
    FInternalFlags := FInternalFlags or $80
  else if Abs(ArcCos(-vNormal2.Z / vLen2)) < cnstPiDiv2 then
    FInternalFlags := FInternalFlags or $20;
end;

procedure TsgDXFSolid.FreeReferences;
begin
  inherited FreeReferences;
  DisposeAndNil(FMatrix);
end;

function TsgDXFSolid.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlPoint2:
      Point2 := ANode.ValueAsFPoint;
    xmlPoint3:
      Point3 := ANode.ValueAsFPoint;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

{ TsgDXFTrace }

function TsgDXFTrace.GetEntType: TsgCADEntities;
begin
  Result := ceTrace;
end;

{ TsgDXF3dFace }

function TsgDXF3dFace.GetEntType: TsgCADEntities;
begin
  Result := ce3dFace;
end;

function TsgDXF3dFace.GetFlags: Integer;
begin
  Result := FFlags;
end;

procedure TsgDXF3dFace.SetFlags(const Value: Integer);
begin
  FFlags := Value;
end;

{ TsgSTL3dFace }

procedure TsgSTL3dFace.CalcState;
begin
  inherited CalcState;
  FInternalFlags := FInternalFlags and not $10;
end;

{ TsgDXFSortEntsTable }

procedure TsgDXFSortEntsTable.ClearReferences;
begin
  inherited ClearReferences;
  FHandlesNew.Clear;
  FHandlesOld.Clear;
end;

constructor TsgDXFSortEntsTable.Create;
begin
  inherited Create;
  FHandlesOld := TsgInt64List.Create;
  FHandlesNew := TsgInt64List.Create;
end;

procedure TsgDXFSortEntsTable.FindMinMaxHandles(const AEntities: TList;
  var AHandleMin, AHandleMax: UInt64);
var
  I: Integer;
  vHandle: UInt64;
  vEnt: TsgDXFEntity;
begin
  AHandleMin := TsgDXFEntity(AEntities[0]).Handle;
  AHandleMax := AHandleMin;
  for I := 0 to FHandlesOld.Count - 1 do
  begin
    vHandle := FHandlesOld[I];
    // this copy variable because GetItem inline function
    SetMinMaxUInt64(vHandle, AHandleMin, AHandleMax);
    vHandle := FHandlesNew[I];
    // this copy variable because GetItem inline function
    SetMinMaxUInt64(vHandle, AHandleMin, AHandleMax);
  end;
  for I := 0 to AEntities.Count - 1 do
  begin
    vEnt := TsgDXFEntity(AEntities.List[I]);
    SetMinMaxUInt64(vEnt.Handle, AHandleMin, AHandleMax);
    if vEnt.EntType = ceViewport then
    begin
      TsgDXFViewport(vEnt).FOrdIndex := -1;
    end;
  end;
end;

procedure TsgDXFSortEntsTable.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FHandlesNew);
  FreeAndNil(FHandlesOld);
end;

procedure TsgDXFSortEntsTable.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(SortObject) and (SortObject.ClassType = TsgLinkObject) then
    SortObject := TsgDXFEntity(TsgLinkObject(SortObject)
      .GetObject(AConverter.Sections[csBlockRecords]));
  if Assigned(SortObject) and (SortObject.ClassType = TsgDXFBlockRecord) then
    SortObject := TsgDXFBlockRecord(SortObject).Block;
end;

procedure TsgDXFSortEntsTable.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
end;

function TsgDXFSortEntsTable.ReplaceHandle(AEntity: TsgDXFEntity): Boolean;
var
  vIndexOld: Integer;
begin
  vIndexOld := FHandlesOld.IndexOf(AEntity.Handle);
  Result := vIndexOld > -1;
  if Result then
    AEntity.Handle := FHandlesNew[vIndexOld];
end;

procedure TsgDXFSortEntsTable.ReplaceHandles(const AEntities: TList;
  const ACurrent, ANew: TsgInt64List);
var
  I, J, vMin, vMax: Integer;
  vHandles: TsgInt64List;
begin
  vHandles := TsgInt64List.Create;
  try
    vHandles.Count := AEntities.Count;
    for I := 0 to AEntities.Count - 1 do
      vHandles[I] := TsgDXFEntity(AEntities.List[I]).Handle;
    for I := 0 to ACurrent.Count - 1 do
    begin
      vMin := 0;
      vMax := AEntities.Count - 1;
      while (vMin <= vMax) do
      begin
        J := (vMax + vMin) shr 1;
        case CompareHandles(ACurrent[I], vHandles[J]) of
          + 1:
            vMin := J + 1;
          -1:
            vMax := J - 1
        else
          TsgDXFEntity(AEntities.List[J]).Handle := ANew[I];
          Break;
        end;
      end;
    end;
  finally
    vHandles.Free;
  end;
end;

procedure TsgDXFSortEntsTable.SortByQwickMetod(const AEntities: TList);
begin
  QSortList(AEntities, CompareHandleEntities);
  ReplaceHandles(AEntities, FHandlesOld, FHandlesNew);
  QSortList(AEntities, CompareHandleEntities);
  ReplaceHandles(AEntities, FHandlesNew, FHandlesOld);
end;

function TsgDXFSortEntsTable.SortEntities(const AGroup: TsgDXFEntity): Boolean;
begin
  Result := False;
  if AGroup is TsgDXFGroup then
  begin
    TsgDXFGroup(AGroup).FViewPortOrdIndex := -1;
    TsgDXFGroup(AGroup).FViewPortWithMinIndex := nil;
    SortEntitiesList(TsgDXFGroup(AGroup).FEntities);
    Result := True;
  end;
end;

procedure TsgDXFSortEntsTable.SortEntitiesList(const AEntities: TList);
var
  vHandleMin, vHandleMax, vHandleSize: UInt64;
begin
  if (AEntities.Count < 2) or (FHandlesOld.Count < 1) then
    Exit;
  FindMinMaxHandles(AEntities, vHandleMin, vHandleMax);
  vHandleSize := vHandleMax - vHandleMin;
  if (vHandleSize > 0) and (vHandleSize < 5000000) then
  // maximum size of memory in byte
    SortSmallList(AEntities, vHandleMin, vHandleMax)
  else
    SortByQwickMetod(AEntities);
end;

procedure TsgDXFSortEntsTable.SortSmallList(const AEntities: TList;
  const AHandleMin, AHandleMax: UInt64);
var
  I, J, K: Integer;
  vListOfHandle, vListOfHandleNew, vEntList: TList;
begin
  vListOfHandle := TList.Create;
  vListOfHandle.Count := AHandleMax - AHandleMin + 1;
  vListOfHandleNew := TList.Create;
  vListOfHandleNew.Count := vListOfHandle.Count;
  try
    for I := 0 to AEntities.Count - 1 do
    begin
      J := TsgDXFEntity(AEntities.List[I]).Handle - AHandleMin;
      vListOfHandle.List[J] := AEntities.List[I];
      vListOfHandleNew.List[J] := AEntities.List[I];
    end;
    for I := 0 to FHandlesOld.Count - 1 do
    begin
      if FHandlesOld[I] = 0 then
        Continue;
      J := FHandlesOld[I] - AHandleMin;
      K := FHandlesNew[I] - AHandleMin;
      if vListOfHandleNew.List[K] = vListOfHandle.List[J] then
        Continue;
      if vListOfHandleNew.List[K] = nil then
        vListOfHandleNew.List[K] := vListOfHandle.List[J]
      else
      begin
        if not(TObject(vListOfHandleNew.List[K]) is TList) then
        begin
          vEntList := TList.Create;
          vEntList.Add(vListOfHandleNew.List[K]);
          vListOfHandleNew.List[K] := vEntList;
        end;
        TList(vListOfHandleNew.List[K]).Add(vListOfHandle.List[J]);
      end;
      if not(TObject(vListOfHandleNew.List[J]) is TList) then
      begin
        if vListOfHandle.List[J] = vListOfHandleNew.List[J] then
          vListOfHandleNew.List[J] := nil;
      end
      else
      begin
        if vListOfHandle.List[J] = TList(vListOfHandleNew.List[J]).First then
          TList(vListOfHandleNew.List[J])[0] := nil;
      end;
    end;
    AEntities.Count := 0;
    for I := 0 to vListOfHandleNew.Count - 1 do
    begin
      if vListOfHandleNew.List[I] <> nil then
      begin
        if not(TObject(vListOfHandleNew.List[I]) is TList) then
          AEntities.Add(vListOfHandleNew.List[I])
        else
        begin
          vEntList := vListOfHandleNew.List[I];
          K := vEntList.Count - 1;
          for J := 0 to K do
            if vEntList.List[J] <> nil then
              AEntities.Add(vEntList.List[J]);
          vEntList.Free;
        end;
      end;
    end;
  finally
    vListOfHandle.Free;
    vListOfHandleNew.Free;
  end;
end;

{ TsgCADBasePolyline }

procedure TsgCADBasePolyline.ClearReferences;
begin
  inherited ClearReferences;
{$IFNDEF EVG}
  if Assigned(FDottedSingPts) and (FDottedSingPts <> FPolyPoints) then
    ClearRecordList(FDottedSingPts);
{$ENDIF}
  if Assigned(FPolyPoints) then
    FPolyPoints.Clear;
end;

constructor TsgCADBasePolyline.Create;
begin
  inherited Create;
  FPolyPoints := TFPointList.Create;
end;

function TsgCADBasePolyline.GetBox: TFRect;
begin
  Result := FBox;
end;

function TsgCADBasePolyline.GetIsMeshMClosed: Boolean;
begin
  Result := Closed;
end;

function TsgCADBasePolyline.GetIsMeshNClosed: Boolean;
begin
  Result := FFlags and 32 <> 0;
end;

function TsgCADBasePolyline.GetIsPLinegen: Boolean;
begin
  Result := FFlags and 128 <> 0;
end;

function TsgCADBasePolyline.GetIsPolygonMesh: Boolean;
begin
  Result := False;
end;
{$IFNDEF EVG}

function TsgCADBasePolyline.DottedCount: Integer;
begin
  Result := FDottedSingPts.Count;
end; {$ENDIF}

function TsgCADBasePolyline.PointCount: Integer;
begin
  Result := FPolyPoints.Count;
end;

procedure TsgCADBasePolyline.AddZTicks(AList: TFPointList);
var
  I, vCount: Integer;
  vPzTick, vElevation: TFPoint;
  vHasElevation, vHasZTick: Boolean;
begin
  vCount := AList.Count - 1;
  vPzTick := MakeFPoint(0, 0, FZThick);
  vHasZTick := not IsZero(vPzTick.Z); // <> 0;
  vElevation := MakeFPoint(0, 0, GetElevation);
  vHasElevation := not IsZero(vElevation.Z); // <> 0;
  if IsExtruded then
  begin
    DoExtrusion(vPzTick, Extrusion);
    DoExtrusion(vElevation, Extrusion);
  end;
  for I := 0 to vCount do
  begin
    if vHasElevation then
      AList[I] := AddFPoint(AList[I], vElevation);
    if vHasZTick then
      AList.Add(AddFPoint(AList[I], vPzTick));
  end;
end;

procedure TsgCADBasePolyline.ApplyBox;
var
  I: Integer;
begin
  FBox := BadRect;
  for I := 0 to PointCount - 1 do
    ExpandFRect(FBox, Points[I]);
end;

procedure TsgCADBasePolyline.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgCADBasePolyline then
    FFlags := TsgCADBasePolyline(Source).FFlags;
end;

function TsgCADBasePolyline.HasWidth(const AFull: Boolean = True): Boolean;
begin
  Result := False;
end;
{$IFNDEF EVG}

procedure TsgCADBasePolyline.CreateDottedList;
begin
  if Lines.IsSolid or IsPolygonMesh then
  begin
    if (FDottedSingPts <> nil) and (FDottedSingPts <> FPolyPoints) then
      FreeRecordList(FDottedSingPts);
    FDottedSingPts := FPolyPoints;
  end
end; {$ENDIF}

procedure TsgCADBasePolyline.DoExtrusions;
var
  I: Integer;
  vExtrusion: TFPoint;
begin
  if IsExtruded then
  begin
    vExtrusion := Extrusion;
    for I := 0 to FPolyPoints.Count - 1 do
      DoExtrusion(FPolyPoints.List^[I], vExtrusion);
  end;
end;

procedure TsgCADBasePolyline.DoZThickAndElevation;
// Converts to polygon mesh if thickness (code 39) is present
begin
  if (not(IsPolyZThickness or (GetElevation <> 0))) or IsPolygonMesh then
    Exit;
{$IFNDEF EVG}
  AddZTicks(FDottedSingPts); // evg???
  if FDottedSingPts <> FPolyPoints then
{$ENDIF}// For correct calculation of FBox
    AddZTicks(FPolyPoints);
end;

// change in future versiojn
procedure TsgCADBasePolyline.DoZThickness(const APointsCounts: TsgIntegerList);
var
  vList: TFPointList;
  vMaxNumDottedLines: Integer;
begin
  // evg:
  if IsPolyZThickness and not Lines.IsSolid then
  begin
    vList := TFPointList.Create;
    vMaxNumDottedLines := iMaxNumDottedLines;
    try
      iMaxNumDottedLines := vMaxNumDottedLines div 8;
      if Assigned(APointsCounts) then
        Lines.Vertexes(PolyPoints, APointsCounts, vList,
          Closed or IsMeshNClosed)
      else
        Lines.Curve(PolyPoints, vList, Closed or IsMeshNClosed);
      PolyPoints.Assign(vList);
      FFlags := FFlags or cnstPolyPointsNotSolid;
    finally
      iMaxNumDottedLines := vMaxNumDottedLines;
      vList.Free;
    end;
  end; // evg
end;

procedure TsgCADBasePolyline.FreeReferences;
begin
  inherited FreeReferences;
{$IFNDEF EVG}
  if Assigned(FDottedSingPts) and (FDottedSingPts <> FPolyPoints) then
    FreeAndNil(FDottedSingPts);
{$ENDIF}
  FreeAndNil(FPolyPoints);
end;

function TsgCADBasePolyline.GetBoxPoints(Proc: TFPointProc;
  Full: Boolean): Boolean;
var
  I: Integer;
  vPoints: TFPointList;
begin
{$IFNDEF EVG}
  vPoints := DottedSingPts;
{$ELSE}
  vPoints := PolyPoints;
{$ENDIF}
  Result := Full and (FBox.Right >= FBox.Left) and
    (vPoints.Count <= cIPointsCnt);
  if not Result then
    inherited GetBoxPoints(Proc, Full)
  else
    for I := 0 to vPoints.Count - 1 do
      Proc(vPoints[I]);
end;

function TsgCADBasePolyline.GetClosed: Boolean;
begin
  Result := not(FFlags and 1 = 0);
end;

function TsgCADBasePolyline.GetElevation: Double;
begin
  Result := 0;
end;

function TsgCADBasePolyline.GetFlags: Integer;
begin
  Result := FFlags;
end;

function TsgCADBasePolyline.GetPolySign: Integer;
begin
  if FFlags and cnstPolySignPlus <> 0 then
    Result := +1
  else if FFlags and cnstPolySignMinus <> 0 then
    Result := -1
  else
    Result := 0;
end;

{$IFNDEF EVG}

function TsgCADBasePolyline.GetDottedPoint(Index: Integer): TFPoint;
begin
  Result := PFPoint(DottedSingPts[Index])^;
end; {$ENDIF}

function TsgCADBasePolyline.GetPolyPoint(Index: Integer): TFPoint;
begin
  Result := PolyPoints[Index];
end;

function TsgCADBasePolyline.IsPathEvacuation: Boolean;
begin
  Result := Flags and cnstPathEvacuationFlag <> 0;
end;

function TsgCADBasePolyline.IsPolyPointsSolid: Boolean;
begin
  Result := (FFlags and cnstPolyPointsNotSolid) = 0;
end;

function TsgCADBasePolyline.GetIsPolyZThickness: Boolean;
begin
  Result := FZThick <> 0;
end;

function TsgCADBasePolyline.GetArea: Double;
begin
  Result := 0; // change in future version
end;

function TsgCADBasePolyline.GetLength: Double;
begin
  Result := 0; // change in future version
end;

procedure TsgCADBasePolyline.LoadedInternal(AConverter: TsgDXFConverter);
var
  vLTScale: Single;
begin
  FBox := BadRect;
  if Layer = nil then
    Layer := AConverter.LayerByName('0');
  if not Assigned(LineType) then
    LineType := AConverter.LTypeByName(sByLayer);
  FFlags := FFlags and (not cnstPolyPointsNotSolid);
  // clear flag by IsPolyPointsSolid
  vLTScale := Lines.Scale;
  Lines.Scale := vLTScale * AConverter.GetLTScale * LineTypeScale;
  try
    ReloadPolyPoints;
{$IFNDEF EVG} CreateDottedList; {$ENDIF}
    DoZThickAndElevation;
    ApplyBox;
  finally
    Lines.Scale := vLTScale;
  end;
end;

procedure TsgCADBasePolyline.ReloadPolyPoints;
begin
  FPolyPoints.Clear(False);
{$IFNDEF EVG} if FDottedSingPts <> FPolyPoints then
    FreeRecordList(FDottedSingPts)
  else
    FDottedSingPts := nil; {$ENDIF}
end;

procedure TsgCADBasePolyline.SetClosed(const AClosed: Boolean);
begin
  FFlags := (FFlags and -2) or Byte(AClosed);
end;

procedure TsgCADBasePolyline.SetFlags(const Value: Integer);
begin
  FFlags := Value;
end;

procedure TsgCADBasePolyline.SetPolySign(const AValue: Integer);
var
  vSign: Integer;
begin
  if AValue > 0 then
    vSign := cnstPolySignPlus
  else if AValue < 0 then
    vSign := cnstPolySignMinus
  else
    vSign := 0;
  FFlags := FFlags and not(cnstPolySignPlus or cnstPolySignMinus);
  FFlags := (FFlags and 127) or vSign;
end;

procedure TsgCADBasePolyline.SetPLineGen(const APLineGen: Boolean);
begin
  FFlags := (FFlags and (not 128)) or (Ord(APLineGen) shl 7);
end;

{ TsgDXFPolyline }

procedure TsgDXFPolyline.Clear(const ADoFree: Boolean);
begin
  inherited Clear(ADoFree);
  ClearEntCollection(FEntities, ADoFree);
end;

procedure TsgDXFPolyline.ClearReferences;
begin
  inherited ClearReferences;
  if Assigned(FArrows) then
    FArrows.Clear;
  ClearList(FPolyLineEntities);
  if Assigned(FPolyFaceVertexIndexes) then
    FPolyFaceVertexIndexes.Clear;
  if Assigned(FPointsCounts) then
    FPointsCounts.Clear;
end;

constructor TsgDXFPolyline.Create;
begin
  inherited Create;
  FEntities := TListNotify(TListNotify.CreateList(ListNotify));
  FPointsCounts := TsgIntegerList.Create;
  // evg   !!! only for linetyped need to be created!!
end;

function TsgDXFPolyline.DeleteEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := FEntities[AIndex];
  FEntities.Delete(AIndex);
end;

function TsgDXFPolyline.GetCount: Integer;
begin
  Result := GetEntities.Count;
end;

function TsgDXFPolyline.GetElevation: Double;
begin
  Result := FPoint.Z;
end;

function TsgDXFPolyline.GetEntities: TList;
begin
  if Assigned(Converter) and (Converter.AllArcsAsCurves = False) then
    Result := FPolyLineEntities
  else
    Result := FEntities;
end;

function TsgDXFPolyline.GetEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := GetEntities[AIndex];
end;

function TsgDXFPolyline.GetIsPolygonMesh: Boolean;
begin
  Result := (FMeshM > 1) and (FMeshN > 1);
  if FPolyPoints <> nil then
    Result := Result and (FMeshM * FMeshN = FPolyPoints.Count);
end;

function TsgDXFPolyline.GetBulgeHeight(const AIndex: Integer): Double;

  function GetHeight(const V1, V2: TsgDXFVertex): Double;
  begin
    Result := 0.5 * V1.Bulge * DistanceFPoint(V1.Point, V2.Point);
  end;

begin
  Result := 0;
  if AIndex <= FEntities.Count - 2 then
    Result := GetHeight(FEntities.List[AIndex], FEntities.List[AIndex + 1])
  else if Closed then
    Result := GetHeight(FEntities.List[AIndex], FEntities.List[0]);
end;

function TsgDXFPolyline.GetIsPolyFaceMesh: Boolean;
begin
  Result := (FPolyFaceVertexIndexes <> nil) and (FFlags = 64) and
    (((FMeshM > 1) and (FMeshN >= 1)) or (FPolyFaceVertexIndexes.Count >= 2));
end;

procedure TsgDXFPolyline.AssignEntity(Source: TsgDXFEntity);
var
  vPoly: TsgDXFPolyline absolute Source;
  I, Cnt: Integer;
  V: TsgDXFVertex;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFPolyline then
  begin
    FreeAndNil(FArrows);
    Clear;
    FEntities.Capacity := vPoly.FEntities.Count;
    Cnt := FEntities.Capacity - 1;
    for I := 0 to Cnt do
    begin
      V := TsgDXFVertex.Create;
      FEntities.Add(V);
      V.AssignEntity(vPoly.FEntities[I]);
    end;
    FMeshM := vPoly.FMeshM;
    FMeshN := vPoly.FMeshN;
    FStartW := vPoly.FStartW;
    FEndW := vPoly.FEndW;
    FGlobalW := vPoly.FGlobalW;
  end;
end;

function TsgDXFPolyline.GetVertex(Index: Integer): TsgDXFVertex;
begin
  Result := FEntities[Index];
end;

procedure TsgDXFPolyline.GetVertexListForPolyFaceMesh(AVertexList: TFPointList);
var
  I, K, vIndex, vFirstIndex, vAbsIndex: Integer;
  vPts: array [0 .. 3] of PFPoint;
  vNext: Boolean;
begin
  if Assigned(AVertexList) then
  begin
    if PolyFaceVertexIndexes.Count = 0 then
      Exit;
    I := 0;
    repeat
      FillChar(vPts, SizeOf(vPts), 0);
      K := 0;
      vNext := False;
      vFirstIndex := Integer(PolyFaceVertexIndexes[I]);
      repeat
        vIndex := Integer(PolyFaceVertexIndexes[I]);
        vAbsIndex := Abs(vIndex) - 1;
        if (vAbsIndex >= 0) and (vAbsIndex < PolyPoints.Count) then
        begin
          vPts[K] := @PolyPoints.List[vAbsIndex];
          Inc(K);
        end
        else
          vNext := True;
        Inc(I);
        if (K = 4) and (vIndex = -vFirstIndex) then
          vNext := True;
      until vNext or (I >= PolyFaceVertexIndexes.Count) or (K = 4);
      if (vPts[0] <> nil) and (vPts[1] <> nil) and (vPts[2] <> nil) then
      begin
        AVertexList.Add(vPts[0]^);
        AVertexList.Add(vPts[1]^);
        AVertexList.Add(vPts[2]^);
        if vPts[3] <> nil then
        begin
          AVertexList.Add(vPts[0]^);
          AVertexList.Add(vPts[2]^);
          AVertexList.Add(vPts[3]^);
        end;
      end;
    until (I >= PolyFaceVertexIndexes.Count);
  end;
end;

procedure TsgDXFPolyline.GetVertexListForPolygonMesh(MeshM, MeshN: Integer;
  AVertexList: TFPointList; AVertexIndexList: TsgIntegerList);
var
  I, J, K: Integer;
  vVector1, vVector2: TFPoint;

  procedure SolidMeshIndex(M, N: Integer; MeshNClosed, MeshMClosed: Boolean;
    AVertexIndexList: TsgIntegerList);
  var
    I, J, K: Integer;
  begin
    for J := 0 to M - 2 do
    begin
      K := J * N;
      for I := 0 to N - 2 do
      begin
        AVertexIndexList.AppendArray([K, K + 1, K + 1 + N]);
        AVertexIndexList.AppendArray([K, K + 1 + N, K + N]);
        Inc(K);
      end;
      if MeshNClosed then
      begin
        AVertexIndexList.AppendArray([K, J * N, (J + 1) * N]);
        AVertexIndexList.AppendArray([K, (J + 1) * N, (J + 2) * N - 1]);
      end;
    end;
    if MeshMClosed then
      for J := 0 to N - 2 do
      begin
        AVertexIndexList.AppendArray([J, (M - 1) * N + J, (M - 1) * N + J + 1]);
        AVertexIndexList.AppendArray([J, (M - 1) * N + J + 1, J + 1]);
      end;
  end;

begin
  if Assigned(AVertexList) and Assigned(AVertexIndexList) then
  begin
    // Add Vertex
    for I := 0 to PolyPoints.Count - 1 do
      AVertexList.Add(PolyPoints[I]);

    if Lines.IsSolid or (IsPolygonMesh and (not IsPolyZThickness)) then
      SolidMeshIndex(MeshM, MeshN, IsMeshNClosed, IsMeshMClosed,
        AVertexIndexList)
    else
    begin
      for I := 0 to MeshM - 2 do
      begin
        K := I * MeshN;
        J := 0;
        while J < MeshN - 1 do
        begin
          vVector1 := AVertexList[K + J];
          vVector2 := AVertexList[K + J + 1];
          if (vVector1.X <> vVector2.X) or (vVector1.Y <> vVector2.Y) or
            (vVector1.Z <> vVector2.Z) then
          begin
            AVertexIndexList.AppendArray([K + J, K + J + 1, K + MeshN + J + 1]);
            AVertexIndexList.AppendArray([K + J, K + MeshN + J + 1,
              K + MeshN + J]);
          end;
          Inc(J, 2);
        end;
      end;
    end;
  end;
end;

function TsgDXFPolyline.HasWidth(const AFull: Boolean = True): Boolean;
var
  I: Integer;
  V: TsgDXFVertex;
begin
  Result := (GlobalWidth <> 0) or (StartWidth <> 0) or (EndWidth <> 0);
  if (not Result) and AFull then
  begin
    for I := 0 to Count - 1 do
    begin
      V := Vertexes[I];
      Result := (V.StartWidth <> 0) or (V.EndWidth <> 0);
      if Result then
        Break;
    end;
  end;
end;

procedure TsgDXFPolyline.DoVertexes;
var
  I, J: Integer;
  vPolyPoints, vDottedSingPts: TFPointList;
  Pt1, Pt2: TFPoint;
  vBulge: Double;
  vIsExtruded: Boolean;
  vExtrusion: TFPoint;

  procedure CreateLineByimImport;
  var
    vLine: TsgDXFLine;
  begin
    vLine := TsgDXFLine.Create;
    Converter.DoCreate(vLine);
    vLine.AssignEntity(Self);
    vLine.Visibility := Visibility;
    vLine.Point := Pt1;
    DoExtrusion(vLine.FPoint, Self.Extrusion); // Point must be extruded
    vLine.Point1 := Pt2;
    DoExtrusion(vLine.FPoint1, Self.Extrusion); // Point1 must be extruded
    vLine.Loaded(Converter);
    if FPolyLineEntities = nil then
      FPolyLineEntities := TList.Create;
    FPolyLineEntities.Add(vLine);
  end;
{ evg
  procedure CopyData(ASource, AReceiver: TList);
  var
  J: Integer;
  begin
  for J := 0 to ASource.Count - 1 do
  AReceiver.Add(ASource[J]);
  end; }

  procedure AddPolyFaceVertex(AIndex: Integer);
  begin
    if FPolyFaceVertexIndexes = nil then
      FPolyFaceVertexIndexes := TList.Create;
    FPolyFaceVertexIndexes.Add(Pointer(Vertexes[AIndex].PolyFaceVertexIndex1));
    FPolyFaceVertexIndexes.Add(Pointer(Vertexes[AIndex].PolyFaceVertexIndex2));
    FPolyFaceVertexIndexes.Add(Pointer(Vertexes[AIndex].PolyFaceVertexIndex3));
    FPolyFaceVertexIndexes.Add(Pointer(Vertexes[AIndex].PolyFaceVertexIndex4));
{$IFDEF EVG}
    FPointsCounts.Add(4);
{$ENDIF}
  end;

// Aplies extrusion for the point
  procedure ApplyExtrusion(var APoint: TFPoint);
  begin
    if (GetEntType <> ceLWPolyline) and (Elevation <> 0) then
    begin
      if Is3dPolyline then
        APoint.Z := APoint.Z - Elevation
      else
        APoint.Z := 0;
    end;
    if vIsExtruded then
      DoExtrusion(APoint, vExtrusion);
  end;

var
  vIsPolygonMesh: Boolean;
  vNumberOfCircleParts: Integer;
begin
  FPointsCounts.Count := 0;
  vIsPolygonMesh := FMeshM * FMeshN = FEntities.Count;
  vIsExtruded := IsExtruded;
  vExtrusion := Extrusion;
  if vIsPolygonMesh then
  begin
    for I := 0 to FEntities.Count - 1 do
    begin
      if Vertexes[I].IsSplineFrameControlPoint then
      begin
{$IFDEF EVG}
        FPointsCounts.Add(-1);
{$ENDIF}
        Continue;
      end;
      if not Vertexes[I].IsPolyfaceMeshVertex then
      begin
        FPolyPoints.Add(Vertexes[I].Point);
{$IFDEF EVG}
        FPointsCounts.Add(1);
{$ENDIF}
      end
      else
        AddPolyFaceVertex(I);
    end;
  end
  else
  begin
    if Converter <> nil then
      vNumberOfCircleParts := Converter.NumberOfPartsInCircle
    else
      vNumberOfCircleParts := GetNumberOfCircleParts;
{$IFNDEF EVG} if FDottedSingPts = nil then
      FDottedSingPts := TList.Create
    else
      ClearRecordList(FDottedSingPts); {$ENDIF}
    vDottedSingPts := TFPointList.Create;
    vPolyPoints := TFPointList.Create;
    try
      if FPointsCounts.Capacity < FEntities.Count then
        FPointsCounts.Capacity := FEntities.Count;
      for I := 0 to FEntities.Count - 1 do
      begin
        if Vertexes[I].IsSplineFrameControlPoint then
        begin
{$IFDEF EVG}
          FPointsCounts.Add(-1);
{$ENDIF}
          Continue;
        end;
        if not Vertexes[I].IsPolyfaceMeshVertex then
        begin
          Pt1 := Vertexes[I].Point;
          vBulge := Vertexes[I].Bulge;
          if I = FEntities.Count - 1 then
          begin
            if IsMeshNClosed or Closed then
              Pt2 := Vertexes[0].Point
            else
            begin
              ApplyExtrusion(Pt1);
              FPolyPoints.Add(Pt1);
{$IFDEF EVG}
              FPointsCounts.Add(1);
{$ENDIF}
              Continue;
            end
          end
          else
            Pt2 := Vertexes[I + 1].Point;

          if ComparePoint(@Pt1, @Pt2) then
          begin
            if vBulge = 0 then
            begin
              if (Converter.ImportMode = imImport) then
                CreateLineByimImport;
              ApplyExtrusion(Pt1);
              FPolyPoints.Add(Pt1);
{$IFDEF EVG}
              FPointsCounts.Add(1);
{$ENDIF}
{$IFNDEF EVG}
              if vIsNotSolid then // evg
              begin
                ApplyExtrusion(Pt2);
                Lines.Line(Pt1, Pt2, vDottedSingPts);
                CopyData(vDottedSingPts, FDottedSingPts);
                vDottedSingPts.Clear;
              end; {$ENDIF}
            end
            else // Adds points for arc segments (with 42 code)
            begin
              ApplyBulgeByPoint(Pt1, Pt2, vBulge, vPolyPoints,
                vNumberOfCircleParts);
              for J := 0 to vPolyPoints.Count - 1 do
                ApplyExtrusion(vPolyPoints.List^[J]);
{$IFNDEF EVG}
              if vIsNotSolid then
              begin
                Lines.Curve(vPolyPoints, vDottedSingPts, False);
                CopyData(vDottedSingPts, FDottedSingPts);
                vDottedSingPts.Clear;
              end;
{$ENDIF}
              FPolyPoints.AppendDynArray(vPolyPoints);
{$IFDEF EVG}
              FPointsCounts.Add(vPolyPoints.Count);
{$ENDIF}
              vPolyPoints.Clear(False);
            end;
          end
          else
          begin
            ApplyExtrusion(Pt1);
            FPolyPoints.Add(Pt1);
{$IFDEF EVG}
            FPointsCounts.Add(1);
{$ENDIF}
          end
        end
        else
          AddPolyFaceVertex(I);
      end;
    finally
      vPolyPoints.Free;
      vDottedSingPts.Free;
    end;
  end;
end;

procedure TsgDXFPolyline.DoZThickAndElevation;
begin
  inherited DoZThickAndElevation;
  if (not(IsPolyZThickness or (GetElevation <> 0))) or IsPolygonMesh then
    Exit;
  if Assigned(FArrows) then
    AddZTicks(FArrows);
end;

procedure TsgDXFPolyline.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FEntities);
  FreeAndNil(FArrows);
  FreeAndNil(FPolyFaceVertexIndexes);
  FreeAndNil(FPointsCounts); // evg
end;

function TsgDXFPolyline.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  vGlobalWidth: Double;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlGlobalWidth:
      begin
        vGlobalWidth := ANode.ValueAsDouble;
        if vGlobalWidth < 0 then
        begin
          Result := cnstXML_ERROR;
          DoErrorXMLNode(AResult.Errors, False, ANode, xmlGlobalWidth);
        end
        else if not Polyline3D then
          GlobalWidth := vGlobalWidth;
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure TsgDXFPolyline.ApplyBulgeByPoint(P1, P2: TFPoint; Bulge: Double;
  AList: TFPointList; ANumberOfCircleParts: Integer);
// Adds points for arc segments (with 42 code)
var
  vArc: TsgDXFArc;
  vArcR: TsgArcR;
  vGenerator: TsgGeneratorShapeEdge;
begin
  vGenerator := TsgGeneratorShapeEdge.Create;
  try
    vGenerator.SetBaseList(AList);
    vGenerator.NumberCirclePart := ANumberOfCircleParts;
    vArcR := vGenerator.CreateBulgesArc(P1, P2, Bulge);
  finally
    vGenerator.Free;
  end;
  if Converter.ImportMode = imImport then
  begin
    vArc := TsgDXFArc.Create;
    Converter.DoCreate(vArc);
    vArc.AssignEntity(Self);
    vArc.Layer := Layer;
    vArc.Visibility := Visibility;
    vArc.Point := vArcR.Center;
    vArc.FRadius := vArcR.Radius;
    vArc.FStartAngle := vArcR.AngleS;
    vArc.FEndAngle := vArcR.AngleE;
    vArc.Loaded(Converter);
    if FPolyLineEntities = nil then
      FPolyLineEntities := TList.Create;
    FPolyLineEntities.Add(vArc);
  end;
end;

procedure TsgDXFPolyline.DoArrows(const ALines: TsgLines;
  const AMatrix: PFMatrix);
var
  vCreatorSegments: TsgCreatorSegments;
begin
  FreeAndNil(FArrows);
  if HasWidth then
  begin
    vCreatorSegments := TsgCreatorSegments.Create(TsgDXFLWPolyline(Self),
      ALines, AMatrix);
    try
      vCreatorSegments.LoadSegments;
    finally
      vCreatorSegments.Free;
    end;
  end;
end;

function TsgDXFPolyline.GetGlobalWidth: Double;
begin
  Result := FGlobalW;
end;

procedure TsgDXFPolyline.SetBulgeHeight(const AIndex: Integer;
  const AHeight: Double);

  procedure SetHeight(const V1, V2: TsgDXFVertex; const H: Double);
  var
    vD: Double;
  begin
    vD := DistanceFPoint(V1.Point, V2.Point);
    if vD > fDoubleResolution then
      V1.Bulge := 2 * H / vD;
  end;

begin
  if AIndex <= FEntities.Count - 2 then
    SetHeight(FEntities.List[AIndex], FEntities.List[AIndex + 1], AHeight)
  else if Closed then
    SetHeight(FEntities.List[AIndex], FEntities.List[0], AHeight);
end;

procedure TsgDXFPolyline.SetElevation(const AValue: Double);
begin
  FPoint.Z := AValue;
end;

procedure TsgDXFPolyline.SetEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity);
begin
  GetEntities[AIndex] := AEntity;
end;

procedure TsgDXFPolyline.SetGlobalWidth(AValue: Double);
begin
  FGlobalW := AValue;
end;

procedure TsgDXFPolyline.SetPointsCounts(const Value: TsgIntegerList);
begin
  FPointsCounts := Value;
end;

procedure TsgDXFPolyline.SetPolyline3D(const Value: Boolean);
begin
  FFlags := (FFlags and (not 8)) or (Ord(Value) shl 3);
end;

function TsgDXFPolyline.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  if IsFullPropsOrXMLHelp(AMode) or ((not Polyline3D) and (GlobalWidth <> 0))
  then
    ANode.AddAttribNV(cnstXMLNames[xmlGlobalWidth].Name).ValueAsDouble :=
      GlobalWidth;
end;

procedure TsgDXFPolyline.ApplyBox;
var
  I: Integer;
begin
  inherited ApplyBox;
  if FArrows <> nil then
    for I := FArrows.Count - 1 downto 0 do
      ExpandFRect(FBox, FArrows[I]);
  // AddThickness(FBox);
end;

function TsgDXFPolyline.GetArea: Double;
var
  vCount: Integer;
begin
  vCount := -1;
  if ZThick <> 0 then
    vCount := PolyPoints.Count div 2;
  Result := GetAreaOfList(PolyPoints, vCount);
end;

function TsgDXFPolyline.GetLength: Double;
var
  vCount: Integer;
begin
  vCount := -1;
  if ZThick <> 0 then
    vCount := PolyPoints.Count div 2;
  Result := GetPerimeterOfList(PolyPoints, Closed, vCount);
end;

procedure TsgDXFPolyline.ReloadPolyPoints;
begin
  inherited ReloadPolyPoints;
  FPolyFaceVertexIndexes.Free;
  FPolyFaceVertexIndexes := nil;
  FreeList(FPolyLineEntities);
  if FEntities.Count = 0 then
    Exit;
  DoVertexes;
  DoZThickness(PointsCounts);
  FreeAndNil(FArrows);
  DoArrows(nil, nil); // calc by box
end;

function TsgDXFPolyline.IndexOfEntity(const AEntity: TsgDXFEntity): Integer;
begin
  Result := FEntities.IndexOf(AEntity);
end;

function TsgDXFPolyline.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  Result := AEntity.ClassType = TsgDXFVertex;
  if Result then
  begin
    if Is3dPolyline then
      TsgDXFVertex(AEntity).Is3DVertex := True;
    FEntities.Insert(AIndex, AEntity);
  end;
end;

function TsgDXFPolyline.Is3dPolygonMesh: Boolean;
begin
  Result := Flags and 16 <> 0;
end;

function TsgDXFPolyline.Is3dPolyline: Boolean;
begin
  Result := Flags and 8 <> 0;
end;

function TsgDXFPolyline.IsExtruded: Boolean;
begin
  if Is3dPolygonMesh or Is3dPolyline then
    Result := False
  else
    Result := inherited IsExtruded;
end;

procedure TsgDXFPolyline.Iterate(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
var
  I: Integer;
begin
  if AConverter.AllArcsAsCurves = False then
    for I := 0 to PolyLineEntities.Count - 1 do
      TsgDXFEntity(PolyLineEntities[I]).Invoke(AConverter, Proc, FinishProc);
end;

function TsgDXFPolyline.GetEntType: TsgCADEntities;
begin
  Result := cePolyline;
end;

{ TsgDXFLWPolyline }

function TsgDXFLWPolyline.GetEntType: TsgCADEntities;
begin
  Result := ceLWPolyline;
end;

function TsgDXFLWPolyline.HasLineWeight: Boolean;
begin
  Result := not HasWidth(False);
end;

{ TsgDXFSpline }

constructor TsgDXFSpline.Create;
begin
  inherited Create;
  FFit := TFPointList.Create;
  FControls := TFPointList.Create;
  FDegree := 3;
  FKnots := TsgSingleList.Create;
  FWeights := TsgSingleList.Create;
end;

procedure TsgDXFSpline.EndExtData(const AData: TsgCADExtendedData);
begin
  AData.AddString(String_1002, '}');
end;

procedure TsgDXFSpline.AssignEntity(Source: TsgDXFEntity);
var
  vSpline: TsgDXFSpline absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFSpline then
  begin
    FFlagsExtented := FFlagsExtented;
    FDegree := vSpline.FDegree;
    FBeginningTangent := vSpline.FBeginningTangent;
    FEndingTangent := vSpline.FEndingTangent;
    FControls.Assign(vSpline.FControls);
    FFit.Assign(vSpline.FFit);
    FKnots.Assign(vSpline.FKnots);
    FWeights.Assign(vSpline.FWeights);
  end;
end;

procedure TsgDXFSpline.ClearReferences;
begin
  inherited ClearReferences;
  FFit.Clear;
  FControls.Clear;
  FKnots.Clear;
  FWeights.Clear;
end;

function TsgDXFSpline.ControlCount: Integer;
begin
  Result := FControls.Count;
end;

function TsgDXFSpline.FitCount: Integer;
begin
  Result := FFit.Count;
end;

function TsgDXFSpline.KnotCount: Integer;
begin
  Result := FKnots.Count;
end;

function TsgDXFSpline.WeightCount: Integer;
begin
  Result := FWeights.Count;
end;

function TsgDXFSpline.GetFitPoint(Index: Integer): TFPoint;
var
  C: Integer;
  P: TFPoint;
begin
  C := FitCount;
  if Index > C + Ord(Closed) then
    Exit;
  if Index < FFit.Count + Ord(Closed) then
  begin
    if Index = FFit.Count then
      Index := 0;
    Result := FFit[Index];
    Exit;
  end;
  if not Closed and (Index > 0) then
    Inc(Index);
  if Index >= Count then
    Dec(Index);
  Result := Controls[Index];
  if not Closed and ((Index = 0) or (Index = Count - 1)) then
    Exit;
  if Closed and (Index = Count - 1) then
    Index := 0
  else
    Dec(Index);
  P := Controls[Index];
  Result.X := (Result.X + P.X) / 2;
  Result.Y := (Result.Y + P.Y) / 2;
  Result.Z := (Result.Z + P.Z) / 2;
end;

procedure TsgDXFSpline.ReloadPolyPoints;
var
  I: Integer;
  P: TFPoint;
begin
  if (FFit <> nil) and (FFit.Count > FControls.Count) and (FPolyPoints.Count = 0)
  then
  begin
    FPolyPoints.Clear(False);
    for I := 0 to FFit.Count - 1 do
    begin
      P := FFit[I];
      P.Z := 0;
      FPolyPoints.Add(P);
    end;
    DoExtrusions;
  end;
end;

procedure TsgDXFSpline.AddKnot(const X: Extended);
var
  V: Single;
begin
  V := X;
  FKnots.Add(V);
end;

procedure TsgDXFSpline.AddWeight(const W: Extended);
var
  V: Single;
begin
  V := W;
  FWeights.Add(V);
end;

function TsgDXFSpline.GetIsByAngles: Boolean;
begin
  Result := FFit.Count > FControls.Count;
end;

function TsgDXFSpline.GetKnot(const AIndex: Integer): Single;
begin
  if AIndex < FKnots.Count then
    Result := FKnots[AIndex]
  else
    Result := 0;
end;

procedure TsgDXFSpline.BuildSplineByAngles(const ANumberOfParts: Integer);
var
  Cnt, PtsCount, N: Integer;
  vSegm: Double;
  vFreeBegin, vFreeEnd: Boolean;
  Tau, M, ksi, eta: TsgDoubleList;
  vBeginningTangent, vEndingTangent: TFPoint;

  procedure CreateParameters;
  var
    I: Integer;
  begin
    vFreeBegin := (vBeginningTangent.X = 0) and (vBeginningTangent.Y = 0) and
      (vBeginningTangent.Z = 0);
    vFreeEnd := (vEndingTangent.X = 0) and (vEndingTangent.Y = 0) and
      (vEndingTangent.Z = 0);
    // Parameter tau[I] returns parameter value by nonregular cell
    Tau := TsgDoubleList.Create(Cnt);
    M := TsgDoubleList.Create(Cnt + 1);
    ksi := TsgDoubleList.Create(Cnt + 1);
    eta := TsgDoubleList.Create(Cnt + 1);
    Tau[0] := 0;
    for I := 1 to Cnt - 2 do
      Tau[I] := Tau[I - 1] + DistanceFPoint(FFit[I], FFit[I - 1], 0) / FLen;
    Tau[Cnt - 1] := 1;
  end;

  procedure DestroyParameters;
  begin
    Tau.Free;
    M.Free;
    ksi.Free;
    eta.Free;
  end;

{ Cubic splines in mi-terms
  Axis - must be equal 1,2,3 for X,Y,Z values of TFPoint. }
  procedure DoSpline(Axis: Byte);
  var
    lambda, mu, coef, T: Double;
    I, J: Integer;

    // Returns function value in fit points (X, Y or Z coords of Index-fitpoint)
    // Index= 0..Cnt-1
    function Fi(Index: Integer): TsgFloat;
    begin
      Result := FFit[Index].V[Axis];
    end;
  // Returns value of Tau-parameter for which it is necessary to find value
  // of function, Index= 1..Cnt-1, J=0..cnstPointsInSegment-1
    function XTau(Index, J: Integer): Double;
    begin
      Result := (DistanceFPoint(FFit[Index + 1], FFit[Index], 0) / FLen) * J /
        ANumberOfParts;
    end;
  // h[i]=tau[i+1]-tau[i], Index= 0..Cnt-1
    function Step(Index: Integer): Double;
    begin
      Result := Tau[Index + 1] - Tau[Index];
    end;

  begin
    // The solution of the equations set with a three-diagonal
    // matrix by traversing method
    ksi[0] := 0.0;
    eta[0] := 0.0;
    ksi[1] := -0.5 * Ord(vFreeBegin);
    if vFreeBegin then // coef := 3*(Fi(1)-Fi(0))/Step(0)// mu=1, lambda=0
      eta[1] := 1.5 * (Fi(1) - Fi(0)) / Step(0)
    else // coef := 2*vBeginningTangent.V[Axis]*FLen;// mu=0, lambda=0
      eta[1] := vBeginningTangent.V[Axis] * FLen;
    for I := 1 to Cnt - 1 do
    begin
      if I <> Cnt - 1 then
      begin
        lambda := Step(I) / (Tau[I + 1] - Tau[I - 1]);
        mu := Step(I - 1) / (Tau[I + 1] - Tau[I - 1]);
        coef := 3 * (mu * (Fi(I + 1) - Fi(I)) / Step(I) + lambda *
          (Fi(I) - Fi(I - 1)) / Step(I - 1));
      end
      else
      begin
        mu := 0;
        lambda := Ord(vFreeEnd);
        if vFreeEnd then
          coef := 3 * (Fi(Cnt - 1) - Fi(Cnt - 2)) / Step(Cnt - 2)
          // mu=0, lambda=1
        else
          coef := 2 * vEndingTangent.V[Axis] * FLen; // mu=0, lambda=0
      end;
      ksi[I + 1] := mu / (-2 - lambda * ksi[I]);
      eta[I + 1] := (lambda * eta[I] - coef) / (-2 - lambda * ksi[I]);
    end;
    ksi[Cnt] := 0;
    M[Cnt] := 0.0;
    for I := Cnt - 1 downto 0 do
      M[I] := ksi[I + 1] * M[I + 1] + eta[I + 1];
    for I := 0 to Cnt - 2 do
      for J := 0 to ANumberOfParts - 1 do
      begin
        T := XTau(I, J) / Step(I);
        FPolyPoints.List^[I * ANumberOfParts + J].V[Axis] := Fi(I) * Sqr(1 - T)
          * (1 + 2 * T) + Fi(I + 1) * Sqr(T) * (3 - 2 * T) + M[I] * Step(I) * T
          * Sqr(1 - T) - M[I + 1] * Step(I) * Sqr(T) * (1 - T);
      end;
    FPolyPoints.List^[PtsCount - 1].V[Axis] := Fi(Cnt - 1);
    M.Clear(False);
    ksi.Clear(False);
    eta.Clear(False);
  end;

begin
  vBeginningTangent := FBeginningTangent;
  vEndingTangent := FEndingTangent;
  if (vBeginningTangent.X > 1) or (vBeginningTangent.X < -1) then
    vBeginningTangent.X := 0;
  if (vBeginningTangent.Y > 1) or (vBeginningTangent.Y < -1) then
    vBeginningTangent.Y := 0;
  if (vEndingTangent.X > 1) or (vEndingTangent.X < -1) then
    vEndingTangent.X := 0;
  if (vEndingTangent.Y > 1) or (vEndingTangent.Y < -1) then
    vEndingTangent.Y := 0;

  Cnt := FFit.Count;
  FLen := 0;
  N := 1;
  while N < Cnt { Ord(not Closed) } do
  begin
    vSegm := DistanceFPoint(FFit[N], FFit[N - 1], 0);
    if vSegm > 0 then
    begin
      FLen := FLen + vSegm;
      Inc(N);
    end
    else
    begin // delete bad fits
      FFit.Delete(N);
      Dec(Cnt);
    end;
  end;
  if Cnt < 2 then
    Exit;
  CreateParameters;
  try
    PtsCount := (Cnt - 1) * ANumberOfParts;
    FPolyPoints.Capacity := PtsCount;
    for N := 0 to PtsCount - 1 do
      FPolyPoints.Add(cnstFPointZero);
    for N := 0 to 2 do
      DoSpline(N);
  finally
    DestroyParameters;
  end;
end;
{$IFNDEF EVG}

procedure TsgDXFSpline.CreateDottedList;
begin
  inherited CreateDottedList;
  if not Lines.IsSolid then
  begin
    if (FDottedSingPts = nil) or (FDottedSingPts = FPolyPoints) then
      FDottedSingPts := TList.Create
    else
      ClearRecordList(DottedSingPts);
    Lines.Curve(FPolyPoints, DottedSingPts, Closed);
  end;
end; {$ENDIF}

function TsgDXFSpline.BeginExtData(const AData: TsgCADExtendedData): Boolean;
begin
  AData.AddString(String_1001, GetAppID);
  AData.AddString(String_1002, '{');
  Result := True;
end;

procedure TsgDXFSpline.BuildSplineAsPoly;
var
  I: Integer;
begin
  if Assigned(FFit) then
    for I := 0 to FFit.Count - 1 do
    begin
      if (I = 0) or (not IsEqualFPoints(FPolyPoints.Last, FFit[I])) then
        FPolyPoints.Add(FFit[I]);
    end;
end;

procedure TsgDXFSpline.LoadedInternal(AConverter: TsgDXFConverter);
begin
  FPolyPoints.Clear(False);
  DisposeAndNil(FExtrusion);
  if IsPolyline then
    BuildSplineAsPoly
  else
  begin
    if IsByAngles then
      BuildSplineByAngles(AConverter.NumberOfPartsInSpline)
    else
      GetSpline(AConverter.NumberOfPartsInSpline);
  end;
  inherited LoadedInternal(AConverter);
end;

procedure TsgDXFSpline.GetPoints(Proc: TsgDXFSplineProc;
  XScale, YScale: Extended);
var
  I: Integer;
  P0: TFPoint;
begin
  if FitCount < 2 then
    for I := 0 to ControlCount - 1 do
    begin
      P0 := ControlPoints[I];
      Proc(MakeFPoint(P0.X, P0.Y, P0.Z));
    end;
end;

function TsgDXFSpline.GetControlPoint(Index: Integer): TFPoint;
begin
  Result := FControls[Index];
end;

function TsgDXFSpline.GetDegree: Byte;
begin
  Result := FDegree;
end;

procedure TsgDXFSpline.GetSpline(const ANumberOfParts: Integer);
var
  IncT: Double;
  vControlCount: Integer;
  vGenerator: TsgGeneratorShapeEdge;
  vWeights: TsgSingleList;
begin
  vControlCount := ControlCount;
  if FitCount > vControlCount then
    Exit;
  if Knots.Count <> 0 then
  begin
    vGenerator := TsgGeneratorShapeEdge.Create;
    try
      vGenerator.SetBaseList(FPolyPoints);
      vGenerator.NumberSplinePart := ANumberOfParts;
      if vGenerator.IsBSpline(Degree) then
      begin
        vWeights := nil;
        if IsRational then
          vWeights := FWeights;
        vGenerator.CreateBSpline(FControls, FKnots, vWeights, Degree);
      end
      else
      begin
        IncT := 1 / ANumberOfParts; // := 0.1;
        if (FitCount < 2) and (vControlCount > 4) and
          (ControlPoints[3].X = ControlPoints[4].X) and
          (ControlPoints[3].Y = ControlPoints[4].Y) then
          IncT := 0.01;
        vGenerator.CreateSplineByKnots(FControls, FKnots, IncT);
      end;
    finally
      vGenerator.Free;
    end;
  end
  else
  begin
    FPolyPoints.AppendDynArray(FControls);
    DoExtrusions;
  end;
end;

function TsgDXFSpline.GetWeight(const AIndex: Integer): Single;
begin
  if AIndex < FWeights.Count then
    Result := FWeights[AIndex]
  else
    Result := 0;
end;

function TsgDXFSpline.IsPolyline: Boolean;
begin
  Result := FlagsExtented and 1 <> 0;
end;

function TsgDXFSpline.IsRational: Boolean;
begin
  Result := Flags and 4 <> 0;
end;

function TsgDXFSpline.GetBeginningTangent: TFPoint;
begin
  Result := FBeginningTangent;
end;

procedure TsgDXFSpline.SetBeginningTangent(AValue: TFPoint);
begin
  FBeginningTangent := AValue;
end;

procedure TsgDXFSpline.SetDegree(const Value: Byte);
begin
  FDegree := Value;
end;

function TsgDXFSpline.GetEndingTangent: TFPoint;
begin
  Result := FEndingTangent;
end;

procedure TsgDXFSpline.SetEndingTangent(AValue: TFPoint);
begin
  FEndingTangent := AValue;
end;

procedure TsgDXFSpline.SetKnot(const AIndex: Integer; const Value: Single);
begin
  if AIndex < FKnots.Count then
    FKnots[AIndex] := Value;
end;

procedure TsgDXFSpline.SetWeight(const AIndex: Integer; const Value: Single);
begin
  if AIndex < FWeights.Count then
    FWeights[AIndex] := Value;
end;

function TsgDXFSpline.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
var
  vNode: TsgNode;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  // RemoveProperty(Result, TsgBasePoint);
  ANode.AddAttribNV(cnstXMLNames[xmlDegree].Name).ValueAsInt := FDegree;
  ANode.AddAttribNV(cnstXMLNames[xmlStartTangentVector].Name).ValueAsFPoint :=
    FBeginningTangent;
  ANode.AddAttribNV(cnstXMLNames[xmlEndTangentVector].Name).ValueAsFPoint :=
    FEndingTangent;
  if IsXMLHelp(AMode) then
  begin
    ANode.AddChildNV(cnstXMLNames[xmlControlPoints].Name);
    ANode.AddChildNV(cnstXMLNames[xmlFitPoints].Name);
    ANode.AddChildNV(cnstXMLNames[xmlKnotsPoints].Name);
    ANode.AddChildNV(cnstXMLNames[xmlWeights].Name);
  end
  else
  begin
    if Assigned(FControls) and (FControls.Count > 0) then
    begin
      vNode := ANode.AddChildNV(cnstXMLNames[xmlControlPoints].Name);
      FControls.ToXML(vNode, cnstXMLNames[xmlPoint].Name);
    end;
    if Assigned(FFit) and (Fit.Count > 0) then
    begin
      vNode := ANode.AddChildNV(cnstXMLNames[xmlFitPoints].Name);
      FFit.ToXML(vNode, cnstXMLNames[xmlPoint].Name);
    end;
    if Assigned(FKnots) and (FKnots.Count > 0) then
    begin
      vNode := ANode.AddChildNV(cnstXMLNames[xmlKnotsPoints].Name);
      FKnots.ToXML(vNode, cnstXMLNames[xmlKnot].Name);
    end;
    if Assigned(FWeights) and (FWeights.Count > 0) then
    begin
      vNode := ANode.AddChildNV(cnstXMLNames[xmlWeights].Name);
      FWeights.ToXML(vNode, cnstXMLNames[xmlWeight].Name);
    end;
  end;
end;

procedure TsgDXFSpline.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FFit);
  FreeAndNil(FControls);
  FreeAndNil(FKnots);
  FreeAndNil(FWeights);
end;

function TsgDXFSpline.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlDegree:
      FDegree := ANode.ValueAsInt;
    xmlStartTangentVector:
      FBeginningTangent := ANode.ValueAsFPoint;
    xmlEndTangentVector:
      FEndingTangent := ANode.ValueAsFPoint;
    xmlControlPoints:
      FControls.FromXML(ANode { , AResult } );
    xmlFitPoints:
      FFit.FromXML(ANode { , AResult } );
    xmlWeights:
      FWeights.FromXML(ANode { , AResult } );
    xmlKnotsPoints:
      FKnots.FromXML(ANode { , AResult } );
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFSpline.GetEntType: TsgCADEntities;
begin
  Result := ceSpline;
end;

function TsgDXFSpline.GetExtData(const AData: TsgCADExtendedData): Boolean;
begin
  Result := False;
  if FlagsExtented <> 0 then
  begin
    BeginExtData(AData);
    AData.AddInt16(Integer_1070, Integer_70);
    AData.AddInt(Integer_1071, FlagsExtented);
    EndExtData(AData);
    Result := AData.DataCount > 0;
  end;
end;

{ TsgDXFCircle }

procedure TsgDXFCircle.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFCircle then
    FRadius := TsgDXFCircle(Source).FRadius;
end;

procedure TsgDXFCircle.ReloadPolyPoints;
begin
  DoZThickness(nil);
  DoExtrusions;
end;

procedure TsgDXFCircle.Params(var A, B, AStart, AEnd, ASin, ACos: Double);
begin
  A := Radius;
  B := Radius;
  AStart := 0;
  AEnd := 360;
  ASin := 0;
  ACos := 1;
end;

function TsgDXFCircle.GetRadius: TsgFloat;
begin
  Result := FRadius;
end;

procedure TsgDXFCircle.SetClosed(const AClosed: Boolean);
begin
end;

procedure TsgDXFCircle.SetRadius(AValue: TsgFloat);
begin
  if AValue > fDoubleResolution then
    FRadius := AValue;
end;

function TsgDXFCircle.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  CircleParamsToXMLNode(ANode, AMode);
end;

function TsgDXFCircle.CircleParamsToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := cnstXML_OK;
  ANode.AddAttribNV(cnstXMLNames[xmlRadius].Name).ValueAsDouble := Radius;
  ANode.AddAttribNV(cnstXMLNames[xmlLength].Name).ValueAsDouble := Length;
  ANode.AddAttribNV(cnstXMLNames[xmlArea].Name).ValueAsDouble := Area;
end;

function TsgDXFCircle.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlRadius:
      Radius := ANode.ValueAsDouble;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFCircle.GetArea: Double;
begin
  Result := GetAreaOfCircle(Radius);
end;

function TsgDXFCircle.GetLength: Double;
begin
  Result := GetLengthCircle(Radius);
end;

{$IFNDEF EVG}

procedure TsgDXFCircle.CreateDottedList;
begin
  inherited CreateDottedList;
  if not Lines.IsSolid then
  begin
    if (FDottedSingPts = nil) or (FDottedSingPts = FPolyPoints) then
      FDottedSingPts := TList.Create
    else
      ClearRecordList(DottedSingPts);
    Lines.Curve(FPolyPoints, DottedSingPts, Closed);
  end;
end;
{$ENDIF}

procedure TsgDXFCircle.LoadedInternal(AConverter: TsgDXFConverter);
// Converts CIRCLE (ARC, ELLIPSE) to polyline
var
  A, B, AStart, AEnd, ASin, ACos, X, Y, Delta: Double;
  S, C: Extended;
  I: Integer;
  vPoint: TFPoint;
  vNumberPartsInCircle: Integer;
begin
  FPolyPoints.Clear(False);
  if not(Self is TsgDXFArc) then
  begin
    Closed := True;
    // FFlags := FFlags or 128;
  end;

  FFlags := FFlags or 128;

  Params(A, B, AStart, AEnd, ASin, ACos);
  AStart := Radian(AStart);
  AEnd := Radian(AEnd);
  vNumberPartsInCircle := AConverter.NumberOfPartsInCircle;
  if vNumberPartsInCircle = 0 then
    vNumberPartsInCircle := GetNumberOfCircleParts;
  Delta := (AEnd - AStart) / vNumberPartsInCircle;
  for I := 0 to vNumberPartsInCircle do
  begin
    SinCos(AStart, S, C);
    X := A * C;
    Y := B * S;
    vPoint.X := Point.X + X * ACos - Y * ASin;
    vPoint.Y := Point.Y + X * ASin + Y * ACos;
    vPoint.Z := Point.Z;
    FPolyPoints.Add(vPoint);
    AStart := AStart + Delta;
  end;
  inherited LoadedInternal(AConverter);
end;

function TsgDXFCircle.GetClosed: Boolean;
begin
  Result := True;
end;

function TsgDXFCircle.GetEntType: TsgCADEntities;
begin
  Result := ceCircle;
end;

{ TsgDXFArc }

constructor TsgDXFArc.Create;
begin
  inherited Create;
  FEndAngle := 360;
end;

procedure TsgDXFArc.AssignEntity(Source: TsgDXFEntity);
var
  vArc: TsgDXFArc absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFArc then
  begin
    FEndAngle := vArc.FEndAngle;
    FStartAngle := vArc.FStartAngle;
  end;
end;

function TsgDXFArc.GetHeight: Double;
var
  vP1, vP2, vP3: TFPoint;
  vA: Double;
begin
  vA := GetMiddleAngle(StartAngle, EndAngle);
  vP1 := GetPointOnCircle(Point, Radius, StartAngle);
  vP2 := GetPointOnCircle(Point, Radius, EndAngle);
  vP3 := GetPointOnCircle(Point, Radius, vA);
  Result := DistanceFPoint(MiddleFPoint(vP1, vP2), vP3);
end;

function TsgDXFArc.GetClosed: Boolean;
begin
  Result := IsEqualAngle(FStartAngle, FEndAngle);
end;

function TsgDXFArc.GetEndAngle: TsgFloat;
begin
  Result := FEndAngle;
end;

procedure TsgDXFArc.SetHeight(const AValue: Double);
var
  vP1, vP2, vP3, vCenter: TFPoint;
  vAS, vAE, vAM, vR: Double;
begin
  if Abs(AValue) <= fAccuracy then
    Exit;
  vP1 := GetPointOnCircle(Point, Radius, StartAngle);
  vP2 := GetPointOnCircle(Point, Radius, EndAngle);
  vP3 := GetNormalPt(vP1, vP2, MiddleFPoint(vP1, vP2), AValue);
  if GetCircleParams(vP1, vP2, vP3, vCenter, vR) and (vR < MaxSingle) then
  begin
    Point := vCenter;
    Radius := vR;
    vAS := GetAngleByPoints(vCenter, vP1, False);
    vAE := GetAngleByPoints(vCenter, vP2, False);
    vAM := GetAngleByPoints(vCenter, vP3, False);
    if vAS > vAE then
      SwapSGFloats(vAS, vAE);
    if (vAM < vAS) or (vAM > vAE) then
      SwapSGFloats(vAS, vAE);
    StartAngle := vAS;
    EndAngle := vAE;
  end;
end;

procedure TsgDXFArc.SetEndAngle(AValue: TsgFloat);
begin
  FEndAngle := AValue;
end;

function TsgDXFArc.GetStartAngle: TsgFloat;
begin
  Result := FStartAngle;
end;

procedure TsgDXFArc.SetStartAngle(AValue: TsgFloat);
begin
  FStartAngle := AValue;
end;

function TsgDXFArc.CircleParamsToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited CircleParamsToXMLNode(ANode);
  ANode.AddAttribNV(cnstXMLNames[xmlHeight].Name).ValueAsDouble := GetHeight;
end;

function TsgDXFArc.ToXMLNode(const ANode: TsgNode; const AMode: TsgXMLModes = []
  ): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlEndAngle].Name).ValueAsDouble := FEndAngle;
  ANode.AddAttribNV(cnstXMLNames[xmlStartAngle].Name).ValueAsDouble :=
    FStartAngle;
end;

function TsgDXFArc.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlEndAngle:
      FEndAngle := ANode.ValueAsDouble;
    xmlStartAngle:
      FStartAngle := ANode.ValueAsDouble;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFArc.GetEndingPoint: TFPoint;
begin
  Result := RotPt(FEndAngle);
  DoExtrusion(Result, Extrusion);
end;

function TsgDXFArc.GetStartingPoint: TFPoint;
begin
  Result := RotPt(FStartAngle);
  DoExtrusion(Result, Extrusion);
end;

function TsgDXFArc.GetArea: Double;
var
  vArc: TsgArcR;
begin
  vArc.Center := Point;
  vArc.Radius := Radius;
  vArc.AngleS := StartAngle;
  vArc.AngleE := EndAngle;
  Result := GetAreaOfArc(vArc);
end;

function TsgDXFArc.GetLength: Double;
begin
  Result := GetLengthArc(FRadius, FStartAngle, FEndAngle);
end;

function TsgDXFArc.RotPt(Angle: Extended): TFPoint;
begin
  Angle := Radian(Angle);
  Result.X := Point.X + Radius * Cos(Angle);
  Result.Y := Point.Y + Radius * Sin(Angle);
  Result.Z := Point.Z;
end;

procedure TsgDXFArc.Params(var A, B, AStart, AEnd, ASin, ACos: Double);
begin
  inherited Params(A, B, AStart, AEnd, ASin, ACos);
  AStart := StartAngle;
  AEnd := EndAngle;
  if StartAngle > EndAngle then
    AStart := AStart - Round(StartAngle / 360) * 360;
  if AEnd < AStart then
    AEnd := AEnd + 360;
end;

procedure TsgDXFArc.LoadedInternal(AConverter: TsgDXFConverter);
begin
  Closed := False;
  inherited LoadedInternal(AConverter);
end;

function TsgDXFArc.GetEntType: TsgCADEntities;
begin
  Result := ceArc;
end;

{ TsgDXFEllipse }

constructor TsgDXFEllipse.Create;
begin
  inherited Create;
  FIsExtruded := True;
end;

procedure TsgDXFEllipse.AssignEntity(Source: TsgDXFEntity);
var
  vEllipse: TsgDXFEllipse absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFEllipse then
  begin
    FIsExtruded := vEllipse.FIsExtruded;
    FRadPt := vEllipse.FRadPt;
    FRatio := vEllipse.FRatio;
  end;
end;

procedure TsgDXFEllipse.LoadedInternal(AConverter: TsgDXFConverter);
begin
  // Only for single call in Loaded
  if FIsExtruded and IsExtruded then
  begin
    FIsExtruded := False;
    DoPreExtrusion(FPoint, Extrusion);
    DoPreExtrusion(FRadPt, Extrusion);
  end;
  FRadius := Sqrt(FRadPt.X * FRadPt.X + FRadPt.Y * FRadPt.Y);
  inherited LoadedInternal(AConverter);
end;

procedure TsgDXFEllipse.Params(var A, B, AStart, AEnd, ASin, ACos: Double);
begin
  inherited Params(A, B, AStart, AEnd, ASin, ACos);
  if (EndAngle > StartAngle) and (EndAngle >= 360) then
  begin
    AStart := StartAngle;
    AEnd := EndAngle;
    if AEnd > AStart + 360 then
      AEnd := AStart + 360;
  end;
  B := A * FRatio;
  if Abs(FRadius) > 1E-10 then
  begin
    ASin := FRadPt.Y / FRadius;
    ACos := FRadPt.X / FRadius;
  end
  else
  begin
    ASin := 1.0;
    ACos := 0.0;
  end;
end;

function TsgDXFEllipse.GetAxisAngle: Double;
begin
  if FRadPt.X <> 0 then
    Result := f180DividedByPi * ArcTan2(FRadPt.Y, FRadPt.X)
  else
  begin
    if FRadPt.Y >= 0 then
      Result := 90
    else
      Result := 270;
  end;
end;

function TsgDXFEllipse.GetAxisAngleRad: Double;
begin
  Result := fPiDividedBy180 * GetAxisAngle;
end;

function TsgDXFEllipse.GetRadPt: TFPoint;
begin
  Result := FRadPt;
end;

procedure TsgDXFEllipse.SetRadPt(AValue: TFPoint);
begin
  FRadPt := AValue;
end;

function TsgDXFEllipse.GetRatio: TsgFloat;
begin
  Result := FRatio;
end;

procedure TsgDXFEllipse.SetAxisAngle(const AAngle: Double);
var
  vAngle, vLength: Double;
  vSin, vCos: Extended;
begin
  if sgModAngle(AAngle, vAngle) then
  begin
    vLength := DistanceFVector(FRadPt);
    if vLength > 0 then
    begin
      SinCos(vAngle * fPiDividedBy180, vSin, vCos);
      FRadPt := MakeFPoint(vCos * vLength, vSin * vLength);
    end;
  end;
end;

procedure TsgDXFEllipse.SetAxisAngleRad(const AAngle: Double);
begin
  SetAxisAngle(AAngle * f180DividedByPi);
end;

procedure TsgDXFEllipse.SetRatio(AValue: TsgFloat);
begin
  FRatio := AValue;
end;

function TsgDXFEllipse.CircleParamsToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := cnstXML_OK;
end;

function TsgDXFEllipse.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.RemoveAttributeByName(cnstXMLNames[xmlLineWeight].Name);
  ANode.AddAttribNV(cnstXMLNames[xmlRadPt].Name).ValueAsFPoint := RadPt;
  ANode.AddAttribNV(cnstXMLNames[xmlRatio].Name).ValueAsDouble := Ratio;
end;

function TsgDXFEllipse.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlRadPt:
      RadPt := ANode.ValueAsFPoint;
    xmlRatio:
      Ratio := ANode.ValueAsDouble;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFEllipse.GetEntType: TsgCADEntities;
begin
  Result := ceEllipse;
end;

function TsgDXFEllipse.GetArea: Double;
begin
  Result := 0;
end;

function TsgDXFEllipse.GetLength: Double;
begin
  Result := 0;
end;

{ TsgDXFTable }

function TsgDXFTable.AddItem(const AItem: TsgDXFEntity): Integer;
begin
  Result := FSortEntList.AddObject(AItem.Name, AItem);
end;

procedure TsgDXFTable.ApplyBox;
begin
  // don't need in Box
end;

procedure TsgDXFTable.AssignEntity(Source: TsgDXFEntity);
// var
// I: Integer;
// vTable: TsgDXFTable absolute Source;
begin
  inherited AssignEntity(Source);
  // if Source is TsgDXFTable then
  // begin
  // for future version
  // if vTable.FSortEntList = nil then
  // begin
  // FreeAndNil(FSortEntList);
  // for I := 0 to vTable.Count - 1 do
  // AddEntity(vTable[I]);
  // end
  // else
  // begin
  // if FSortEntList = nil then
  // FSortEntList := TsgStringList.Create;
  // FSortEntList.Assign(vTable.FSortEntList);
  // CopyLists(FEntities, vTable.FEntities);
  // end;
  // end;
end;

procedure TsgDXFTable.Clear(const ADoFree: Boolean);
begin
  FSortEntList.Clear;
  inherited Clear(ADoFree);
end;

procedure TsgDXFTable.ClearReferences;
begin
  inherited ClearReferences;
  FSortEntList.Clear;
end;

constructor TsgDXFTable.Create;
begin
  inherited Create;
  FSortEntList := TsgStringList.Create;
  FSortEntList.CaseSensitive := False;
  FSortEntList.Duplicates := dupAccept; // dupIgnore;
  FSortEntList.Sorted := True;
end;

function TsgDXFTable.DeleteItem(const AItem: TsgDXFEntity): Integer;
begin
  Result := FSortEntList.IndexOfObject(AItem);
  if Result >= 0 then
    FSortEntList.Delete(Result);
end;

function TsgDXFTable.FindEntByName(const AName: string): TsgDXFEntity;
var
  vIndex: Integer;
begin
  Result := nil;
  vIndex := FSortEntList.IndexOf(AName);
  if vIndex > -1 then
    Result := TsgDXFEntity(FSortEntList.Objects[vIndex]);
end;

procedure TsgDXFTable.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FSortEntList);
end;

function TsgDXFTable.GetComplex: Boolean;
begin
  Result := True;
end;

procedure TsgDXFTable.Link(AConverter: TsgDXFConverter);
var
  I: Integer;
begin
  inherited Link(AConverter);
  if FSortEntList.Count <> Count then
  begin
    FSortEntList.Clear;
    for I := 0 to Count - 1 do
      AddItem(Entities[I]);
  end;
end;

procedure TsgDXFTable.ListNotify(Ptr: Pointer; Action: TListNotification);
begin
  case Action of
    lnAdded:
      begin
        inherited ListNotify(Ptr, Action);
        if TsgDXFEntity(Ptr).EntType = ceViewport then
          SetViewPortProperty(TsgDXFViewport(Ptr), False);
        AddItem(TsgDXFEntity(Ptr));
      end;
    lnDeleted, lnExtracted:
      begin
        DeleteItem(TsgDXFEntity(Ptr));
        inherited ListNotify(Ptr, Action);
      end;
  end;
end;

function TsgDXFTable.RenameItem(const AItem: TsgDXFEntity;
  const NewName: string): Boolean;
// var
// vIndex: Integer;
begin
  { Result := False;
    if FSortEntList <> nil then
    begin
    vIndex := FSortEntList.IndexOf(NewName);
    if vIndex < 0 then
    begin
    // NewName is unique of FSortEntList
    vIndex := FSortEntList.IndexOf(AItem.EntName);
    if vIndex >= 0 then
    begin
    FSortEntList.Delete(vIndex);
    FSortEntList.AddObject(NewName, AItem);
    Result := True;
    end
    // else
    // begin
    //   AItem.EntName is not in the list of FSortEntList
    // end
    end
    else
    // NewName differ from AItem.EntName only by charcase
    Result := (FSortEntList.Objects[vIndex] = AItem) and
    (AnsiCompareStr(NewName, AItem.EntName) <> 0);
    end
    else
    begin
    if not FindChildByEntName(Self, NewName, False, vIndex) then
    // NewName is unique from list of FEntities
    Result := True
    else
    // NewName differ from AItem.EntName only by charcase
    Result := (Entities[vIndex] = AItem) and
    (AnsiCompareStr(NewName, AItem.EntName) <> 0);
    end; }
  // if Result then
  AItem.SetName(NewName);
  Result := AItem.Name = NewName;
end;

procedure TsgDXFTable.SetEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity);
begin
  inherited SetEntity(AIndex, AEntity);
end;

function TsgDXFTable.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.RemoveAttributeByName(cnstXMLNames[xmlLayerName].Name);
end;

{ TsgDXFBlock }

constructor TsgDXFBlock.Create;
begin
  inherited Create;
  FXrefPath := '';
  if FBlockRecord = nil then
  begin
    FBlockRecord := TsgDXFBlockRecord(TsgDXFBlockRecord.NewInstance);
    FBlockRecord.Block := Self;
    FBlockRecord.Create;
  end;
end;

procedure TsgDXFBlock.CheckAttdefFlag;
var
  I: Integer;
  vHasConstantAttdef, vHasAnyAttdef: Boolean;
begin
  // bit "0x02" is not set if the block has any attribute definitions
  // that are constant, or has no attribute definitions at all
  vHasConstantAttdef := False;
  vHasAnyAttdef := False;
  I := 0;
  while (I < Count) and not vHasConstantAttdef do
    if Entities[I].EntType = ceAttdef then
    // if Entities[I] is TsgDXFAttdef then
    begin
      vHasAnyAttdef := True;
      if TsgDXFAttdef(Entities[I]).Constant then
        Inc(vHasConstantAttdef)
      else
        Inc(I);
    end
    else
      Inc(I);
  if vHasConstantAttdef or not vHasAnyAttdef then
    SetFlags(GetFlags and not $02)
  else
    SetFlags(GetFlags or $02);
end;

{ procedure TsgDXFBlock.CheckSpecPaperSpaceName;
  //fix export empty block SpecPaperSpace
  var
  vName: string;
  begin
  vName := AnsiUpperCase(FName);
  if (Length(vName) > 0) and (vName[1] = '$') then
  vName[1] := '*';
  if (sModelSpace = vName) or (sPaperSpace = vName) then
  SetSpecPaperSpace(True);
  end; }

procedure TsgDXFBlock.Clear(const ADoFree: Boolean = True);
begin
  inherited Clear(ADoFree);
  IsLoaded := False;
  FBox := cnstBadRect;
  FXref := nil;
  SetFlags(GetFlags and not $02);
end;

procedure TsgDXFBlock.ClearReferences;
var
  I: Integer;
begin
  inherited ClearReferences;
  if Assigned(Layout) then
  begin
    TsgDXFLayout(Layout).FPaperSpaceBlock := nil;
    Layout := nil;
  end;
  if FReferences <> nil then
    for I := FReferences.Count - 1 downto 0 do
      TsgDXFEntity(FReferences[I]).RemoveReferenceNotification(Self);
end;

procedure TsgDXFBlock.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FReferences);
  if Assigned(FBlockRecord) then
    FBlockRecord.FBlock := nil;
  FreeAndNil(FBlockRecord);
end;

procedure TsgDXFBlock.ListNotify(Ptr: Pointer; Action: TListNotification);
begin
  case Action of
    lnAdded:
      begin
        inherited ListNotify(Ptr, Action);
        case TsgDXFEntity(Ptr).EntType of
          ceViewport:
            SetViewPortProperty(TsgDXFViewport(Ptr), True);
          ceAttdef:
            if TsgDXFAttdef(Ptr).Constant then
              SetFlags(GetFlags and not $02)
            else
              SetFlags(GetFlags or $02);
          ceXRef:
            begin
              FXref := TsgDXFXref(Ptr);
              if Assigned(Converter) then
                Converter.GetMainConverter.XRefs.Add(FXref);
            end;
        end;
      end;
    lnExtracted, lnDeleted:
      begin
        case TsgDXFEntity(Ptr).EntType of
          ceAttdef:
            CheckAttdefFlag;
          ceViewport:
            begin
              // FViewPortOrdIndex := -1;
              if Ptr = FViewPortWithMinIndex then
                FViewPortWithMinIndex := nil;
              TsgDXFViewport(Ptr).FOrdIndex := -1;
            end;
          ceXRef:
            begin
              if FXref = Ptr then
              begin
                if Assigned(Converter) then
                  Converter.GetMainConverter.XRefs.Remove(FXref);
                FXref := nil;
              end;
            end;
        end;
        inherited ListNotify(Ptr, Action);
      end;
  end;
end;

procedure TsgDXFBlock.LoadedInternal(AConverter: TsgDXFConverter);
var
  I: Integer;
  vXRef: TsgDXFXref;
  vConv: TsgDXFConverter;
  vList: TList;
  vFind: Boolean;

  function FindXref(AList: TList; var Index: Integer): Boolean;
  begin
    Index := 0;
    Result := False;
    while (Index < AList.Count) and not Result do
      if ExtractFileName(TsgDXFXref(AList[Index]).Path)
        = ExtractFileName(FXrefPath) then
        Inc(Result)
      else
        Inc(Index);
  end;

  procedure InitXref(const ASrc: TsgDXFXref);
  begin
    AddEntity(TsgDXFXref.Create);
    if Assigned(ASrc.CADImage) then
    begin
      FXref.FCADImage := TGraphicClass(ASrc.CADImage.ClassType).Create;
      FXref.FCADImage.Assign(ASrc.CADImage);
    end;
    FXref.FPath := ASrc.Path;
    FXref.FBox := ASrc.Box;
    FXref.Name := ASrc.Name;
  end;

begin
  if IsLoaded then
    Exit;
  if (FXrefPath <> '') and IsBlockByXRef and
    not(IsBlockXrefOverlay and Assigned(AConverter.FContainerXref))
  // internal Xref-XRef overlay
    and (CompareText(ExtractFileName(AConverter.FileName),
    ExtractFileName(FXrefPath)) <> 0) then
  begin
    vList := GlobalLoadingXRefsStack.LockList;
    try
      I := 0;
      vXRef := nil;
      if FindXref(vList, I) then
        vXRef := vList[I];
      if Assigned(vXRef) then
      begin
        vFind := True;
        InitXref(vXRef);
      end
      else
      begin
        vConv := AConverter;
        repeat
          vFind := FindXref(vConv.XRefs, I);
          if not vFind then
            vConv := vConv.FOwnerConverter;
        until vFind or (vConv = nil);
        if vFind then
          InitXref(TsgDXFXref(vConv.XRefs[I]));
      end;
    finally
      GlobalLoadingXRefsStack.UnlockList;
    end;

    if not vFind then
      if ExtractFileName(AConverter.GetMainConverter.FileName) <>
        ExtractFileName(FXrefPath) then
        AddFromXrefPath(AConverter)
      else
      begin
        // breaking circular reference from FXrefPath to AConverter.GetMainConverter.FileName
      end;
  end;
  CheckAttdefFlag;
  { if (Pos(sPaperSpace, UpperCase(FName)) <> 0) and (Count > 0) then
    begin
    FSpecPaperSpace := True;
    inherited Loaded(AConverter);
    FLoaded := True;
    Exit;
    end; }
  inherited LoadedInternal(AConverter);
  // ApplyBox; previous version, in the current version see inherited Loaded(AConverter);
  IsLoaded := True;
  FBlockRecord.Loaded(AConverter);
end;

procedure TsgDXFBlock.SetLayout(const Value: TsgDXFEntity);
begin
  FLayout := Value;
end;

procedure TsgDXFBlock.SetLoaded(const Value: Boolean);
begin
  FInternalFlags := (FInternalFlags and 254) or Byte(Value);
end;

procedure TsgDXFBlock.SetXrefPath(const Value: string);
begin
  FXrefPath := Value;
end;

function TsgDXFBlock.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  if IsFullPropsOrXMLHelp(AMode) or (not IsEqualFPoints(Offset, cnstFPointZero))
  then
    ANode.AddAttribNV(cnstXMLNames[xmlBasePoint].Name).ValueAsFPoint := Offset;
end;

function TsgDXFBlock.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlBasePoint:
      Offset := ANode.ValueAsFPoint;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

{ procedure TsgDXFBlock.SetSpecPaperSpace(const Value: Boolean);
  begin
  FInternalFlags := (FInternalFlags and 253) or (Byte(Value) shl 1);
  end; }

{$IFDEF SG_BTI}

function TsgDXFBlock.GetExtendedData: TObject;
begin
  Result := nil;
end;
{$ENDIF}

function TsgDXFBlock.AddEntity(const AEntity: TsgDXFEntity): Integer;
begin
  Result := AddEntUseInsert(AEntity);
end;

procedure TsgDXFBlock.AddFromXrefPath(AConverter: TsgDXFConverter);
var
  vObj: TObject;
begin
  Clear(True);
  if not Assigned(FXref) then
    AddEntity(TsgDXFXref.Create)
  else
  begin
    FXref.FPath := '';
    FXref.FBox := cnstBadRect;
  end;
  // Clear entities and base point of the block (only for Xref-block)
  FOffset := cnstFPointZero;
  // {For future versions, see DWG12 xrefs} Clear;
  if FXref.AddCADImage(AConverter, FXrefPath, AConverter.FXRefSearchPaths) then
    FXref.LoadedInternal(AConverter)
  else
  begin
    vObj := FXref;
    RemoveEntity(FXref);
    vObj.Free;
  end;
end;

procedure TsgDXFBlock.ApplyBox;
var
  I: Integer;
  vEnt: TsgDXFEntity;
  vAttdef: TsgDXFAttdef absolute vEnt;
  vIns: TsgDXFInsert absolute vEnt;
begin
  FBox := BadRect;
  I := 0;
  while I < Count do // FBox is union of all entities
  begin
    vEnt := Entities[I];
    if vEnt.Visibility = True then
    begin
      if not((vEnt.EntType = ceAttdef) and ((vAttdef.Flags = 0) or
        vAttdef.NotAppear or (vAttdef.Value = ''))) then
      begin
        if vEnt is TsgDXFInsert then
        begin
          if Assigned(vIns.Block) and (vIns.Block.ClassType = TsgLinkObject)
          then
            vIns.Link(Converter);
          if Assigned(vIns.Block) and not vIns.Block.IsLoaded then
            vIns.Resolve(Converter);
          vIns.CheckBlock(Converter);
          UnionFRect(FBox, vEnt.Box);
        end
        else
          UnionFRect(FBox, vEnt.Box);
      end;
    end;
    Inc(I);
  end;
end;

procedure TsgDXFBlock.AssignEntity(Source: TsgDXFEntity);
var
  vXRef: TsgDXFXref;
  vBlock: TsgDXFBlock absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFBlock then
  begin
    vXRef := FXref;
    if Assigned(vXRef) then
      try
        RemoveEntity(vXRef);
      finally
        FreeAndNil(vXRef);
      end;
    FInternalFlags := vBlock.FInternalFlags;
    IsLoaded := False;
    FOffset := vBlock.FOffset;
    FXrefPath := vBlock.FXrefPath;
    FBlockRecord.AssignEntity(vBlock.BlockRecord);
  end;
end;

function TsgDXFBlock.GetBlockRecord: TsgDXFBlockRecord;
begin
  Result := FBlockRecord;
end;

function TsgDXFBlock.GetComplex: Boolean;
begin
  Result := True;
end;

function TsgDXFBlock.GetLayout: TsgDXFEntity;
begin
  Result := FLayout;
end;

function TsgDXFBlock.GetLoaded: Boolean;
begin
  Result := FInternalFlags and 1 <> 0;
end;

function TsgDXFBlock.GetReferences: TsgList;
begin
  if FReferences = nil then
  begin
    FReferences := TsgList.Create;
    FReferences.Sorted := True;
    FReferences.Duplicates := dupIgnore;
  end;
  Result := FReferences;
end;

// function TsgDXFBlock.GetSpecPaperSpace: Boolean;
// begin
// Result := Assigned(FLayout); //Result := FInternalFlags and 2 <> 0;
// end;

function TsgDXFBlock.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  Result := False;
  if Assigned(FLayout) or (not IsLoaded) then
  begin
{$IFDEF sgProt}
    if (Count + 1) and 3 <> 0 then
{$ENDIF}
      Result := inherited InsertEntity(AIndex, AEntity);
  end;
end;

function TsgDXFBlock.GetXrefPath: string;
begin
  Result := FXrefPath;
  if (Length(Result) = 0) and Assigned(FXref) then
    Result := FXref.Path;
end;

function TsgDXFBlock.IsAcadTableBlock: Boolean;
begin
  Result := IsBlockIntetnal;
  if Result then
    Result := (Length(Name) > 2) and (UpCase(Name[2]) = 'T') and
      (IsDigit(Name[3]) or (Pos(sInternalACADTable, Name) = 1));
end;

function TsgDXFBlock.IsBlockByXRef: Boolean;
begin
  Result := (Flags and 36 <> 0);
end;

function TsgDXFBlock.IsBlockIntetnal: Boolean;
begin
  Result := (Flags and 1 <> 0);
  if (not Result) and (Length(Name) > 0) and (Name[1] = cnstInternalBlockPrefix)
  then
    Result := True;
end;

function TsgDXFBlock.IsBlockXrefOverlay: Boolean;
begin
  Result := (Flags and 8 <> 0);
end;

function TsgDXFBlock.IsModalSpaceBlock: Boolean;
var
  vConverter: TsgDXFConverter;
begin
  vConverter := Converter;
  Result := Assigned(vConverter) and (vConverter.LayoutsCount > 0) and
    (Layout = vConverter.Layouts[0]);
end;

function TsgDXFBlock.IterateEx(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc): TList;
var
  I: Integer;
  vEnt: TsgDXFEntity;
begin
  Result := nil;
  for I := 0 to Count - 1 do
  begin
    vEnt := Entities[I];
    if not(vEnt.ClassType = TsgDXFAttdef) then
      vEnt.Invoke(AConverter, Proc, FinishProc)
    else
    begin
      if Result = nil then
        Result := TList.Create;
      Result.Add(vEnt);
    end;
  end;
end;

{ TsgDXFInsert }

procedure TsgDXFInsert.CalculateMatrix;
begin
  InitializeMatrix;
  FMatrix := BuildMatrix(Point, Scale, Extrusion, Reverse(GetBlockOffset),
    Angle, FMatrix);
end;

function TsgDXFInsert.CheckBlock(AConverter: TsgDXFConverter): Boolean;
begin
  LinkBlockRecord(AConverter);
  if Assigned(Block) and not Block.IsLoaded then
  begin
    if Assigned(AConverter.OnLoad) then
      AConverter.OnLoad(Block)
    else
      AConverter.Loads(Block);
  end;
  Result := not((Block = nil) or ((Block.Count = 0) and (FAttribs.Count = 0)));
end;

procedure TsgDXFInsert.Clear(const ADoFree: Boolean);
begin
  inherited Clear(ADoFree);
  ClearEntCollection(FAttribs, ADoFree);
end;

procedure TsgDXFInsert.ClearReferences;
begin
  inherited ClearReferences;
  ReferenceBlockRecord(nil);
  FOwnerInsert := nil;
end;

procedure TsgDXFInsert.CopyItems(const ASource: TsgDXFEntity);
var
  vSrc, vDst: TsgDXFEntity;
  I: Integer;
begin
  for I := 0 to TsgDXFInsert(ASource).Attribs.Count - 1 do
  begin
    vSrc := TsgDXFInsert(ASource).Attribs[I];
    vDst := TsgDXFEntityClass(vSrc.ClassType).Create;
    AssignAttrib(vDst, vSrc);
    Attribs.Add(vDst);
  end;
  DelayedLoadAttribs := Attribs.Count > 0;
end;

constructor TsgDXFInsert.Create;
begin
  inherited Create;
  FScale := cnstFPointSingle;
  FExtrusion := cnstExtrusion;
  FAttribs := TListNotify(TListNotify.CreateList(ListNotify));
  FMatrix := cnstIdentityMat;
end;

procedure TsgDXFInsert.DoDelayedLoad(AConverter: TsgDXFConverter);
begin
  ReloadAttribs(AConverter);
end;

procedure TsgDXFInsert.AssignAttrib(Dest, Source: TsgDXFEntity);
begin
  Dest.AssignEntity(Source);
end;

procedure TsgDXFInsert.AssignEntity(Source: TsgDXFEntity);
var
  vInsert: TsgDXFInsert absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFInsert then
  begin
    FSceneElement := vInsert.FSceneElement;
    // clear attributes
    Clear;
    // copy attributes/items/...
    CopyItems(vInsert);
    // copy block reference/block entities...
    ReferenceBlockRecord(vInsert.BlockRecord);
    // copy single-type properties
    FAngle := vInsert.FAngle;
    FExtrusion := vInsert.FExtrusion;
    FMatrix := vInsert.FMatrix;
    FOwnerInsert := vInsert.FOwnerInsert;
    FScale := vInsert.FScale;
  end;
end;

function TsgDXFInsert.GetCount: Integer;
begin
  Result := FAttribs.Count;
end;

function TsgDXFInsert.GetDelayedLoadAttribs: Boolean;
begin
  Result := FInternalFlags and 1 <> 0;
end;

function TsgDXFInsert.GetEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := TsgDXFEntity(FAttribs[AIndex]);
end;

function TsgDXFInsert.EntName: string;
begin
  if FSceneElement > 0 then
    Result := cnstSceneElement
  else
  begin
    Result := inherited EntName;
    if Block <> nil then
      Result := Result + ' ' + Block.Name;
  end;
end;

function TsgDXFInsert.RealLayer: TsgDXFLayer;
var
  vContainerLayer: TsgDXFLayer;
begin
  Result := Layer;
  if Result <> nil then
  begin
    vContainerLayer := Result.GetContainerLayer;
    if vContainerLayer <> nil then
      Result := vContainerLayer;
  end;
  if ((Result = nil) or (Result.Name = '0')) and (OwnerInsert <> nil) then
    Result := FOwnerInsert.RealLayer;
end;

{ Procedure TsgDXFInsert.ReferenceBlockRecord

  Called from the "AssignEntity".
  Do not call directly }

procedure TsgDXFInsert.ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord);
begin
  BlockRecord := ABlockRecord;
end;

function TsgDXFInsert.FindBlock(AConverter: TsgDXFConverter;
  const AName: string): TsgDXFBlock;
begin
  Result := AConverter.BlockByName(AName);
end;

procedure TsgDXFInsert.Resolve(AConverter: TsgDXFConverter);
// For forward references
begin
  if Assigned(Block) and (Block.ClassType = TsgLinkObject) then
    Block := TsgDXFBlock(TsgLinkObject(Block)
      .GetObject(AConverter.Sections[csBlockRecords]));
  if Assigned(Block) and (Block.ClassType <> TsgLinkObject) then
    if Assigned(AConverter.OnLoad) then
      AConverter.OnLoad(Block)
    else
      Block.Loaded(AConverter);
  LoadedInternal(AConverter);
end;

function TsgDXFInsert.GetAngle: Single;
begin
  Result := FAngle;
end;

function TsgDXFInsert.GetBlock: TsgDXFBlock;
begin
  Result := nil;
  if Assigned(FBlockRecord) then
    Result := FBlockRecord.Block;
end;

function TsgDXFInsert.GetBlockOffset: TFPoint;
begin
  Result := Block.Offset;
  if Block.IsBlockByXRef and (Block.Xref <> nil) and (Block.Xref.CADImage <> nil)
  then
    Result := AddFPoint(Result, TsgCADImage(Block.Xref.CADImage)
      .Converter.HeadVarStruct.InsBase);
end;

function TsgDXFInsert.GetBox: TFRect;
begin
  if Assigned(Block) and (Block.ClassType = TsgLinkObject) then
    Resolve(Converter);
  Result := FBox;
end;

function TsgDXFInsert.Attrib(const S: string; var P: TFPoint): TsgDXFAttrib;
var
  I: Integer;
begin
  for I := 0 to FAttribs.Count - 1 do
  begin
    Result := TsgDXFAttrib(FAttribs[I]);
    if Result.Tag <> S then
      Continue;
    P := Result.FStartPoint;
    Exit;
  end;
  Result := nil;
end;

function TsgDXFInsert.RealColor(AColor: TColor): TColor;
begin
  Result := AColor;
  if (Result <> clByLayer) or (Self = nil) then
    Exit;
  Result := Color;
  if Result = clByLayer then
    Result := FOwnerInsert.RealColor(Result);
end;

procedure TsgDXFInsert.ReloadAttribs(AConverter: TsgDXFConverter);
var
  I: Integer;
begin
  for I := 0 to FAttribs.Count - 1 do
    TsgDXFAttrib(FAttribs[I]).Loaded(AConverter);
end;

procedure TsgDXFInsert.RemoveReferenceNotification(const ARefObj: TsgDXFEntity);
begin
  inherited RemoveReferenceNotification(ARefObj);
  if ARefObj = Block then
    Block := nil;
end;

procedure TsgDXFInsert.SetAngle(const Value: Single);
var
  vAttrib: TsgDXFAttrib;
  Delta, vValue: Double;
  I: Integer;
begin
  if sgModAngle(Value, vValue) then
  begin
    Delta := vValue - FAngle;
    FAngle := vValue;
    for I := 0 to FAttribs.Count - 1 do
    begin
      vAttrib := Attribs[I];
      vAttrib.Point := OffsetFPoint(vAttrib.Point, Point, False);
      vAttrib.Point := RotateFPoint(vAttrib.Point, Delta);
      vAttrib.Point := OffsetFPoint(vAttrib.Point, Point, True);
      if vAttrib.HasSecond then
      begin
        vAttrib.Point1 := OffsetFPoint(vAttrib.Point1, Point, False);
        vAttrib.Point1 := RotateFPoint(vAttrib.Point1, Delta);
        vAttrib.Point1 := OffsetFPoint(vAttrib.Point1, Point, True);
      end;
      vAttrib.Rotation := vAttrib.Rotation + Delta;
    end;
  end;
end;

procedure TsgDXFInsert.SetBlock(const Value: TsgDXFBlock);
begin
  if Assigned(Value) and Value.InheritsFrom(TsgDXFBlock) then
    BlockRecord := Value.BlockRecord
  else
    BlockRecord := TsgDXFBlockRecord(Value);
end;

procedure TsgDXFInsert.SetBlockRecord(const Value: TsgDXFBlockRecord);
begin
  if FBlockRecord <> Value then
  begin
    if Assigned(FBlockRecord) and FBlockRecord.InheritsFrom(TsgDXFBlockRecord)
    then
      FBlockRecord.Block.References.Remove(Self);
    FBlockRecord := Value;
    if Assigned(FBlockRecord) and FBlockRecord.InheritsFrom(TsgDXFBlockRecord)
    then
      FBlockRecord.Block.References.Add(Self);
  end;
end;

procedure TsgDXFInsert.SetDelayedLoadAttribs(const Value: Boolean);
begin
  FInternalFlags := (FInternalFlags and $FE) or Byte(Value);
end;

procedure TsgDXFInsert.SetEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity);
begin
  FAttribs[AIndex] := AEntity;
end;

procedure TsgDXFInsert.SetExtrusion(const Value: TFPoint);
begin
  FExtrusion := Value;
  if (FExtrusion.X = 0) and (FExtrusion.Y = 0) and (FExtrusion.Z = 0) then
    FExtrusion.Z := 1;
end;

procedure TsgDXFInsert.SetLineWeight(Value: Double);
begin
  FLineWeight := Value;
end;

procedure TsgDXFInsert.SetPoint(AValue: TFPoint);
begin
  OffsetAttribs(OffsetFPoint(AValue, Point, False));
  inherited SetPoint(AValue);
end;

procedure TsgDXFInsert.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  LinkBlockRecord(AConverter);
end;

procedure TsgDXFInsert.LinkBlockRecord(AConverter: TsgDXFConverter);
begin
  if Assigned(BlockRecord) and (BlockRecord.ClassType = TsgLinkObject) then
    BlockRecord := TsgDXFBlockRecord(TsgLinkObject(BlockRecord)
      .GetObject(AConverter.Sections[csBlockRecords]));
end;

procedure TsgDXFInsert.LoadedInternal(AConverter: TsgDXFConverter);

  procedure DoAttribsBox;
  var
    I: Integer;
    vAttrib: TsgDXFAttrib;
  begin
    for I := 0 to FAttribs.Count - 1 do
    begin
      vAttrib := FAttribs.List[I];
      if not vAttrib.NotAppear then
        UnionFRect(FBox, vAttrib.FBox);
    end;
  end;

begin
  inherited LoadedInternal(AConverter);
  FBox := BadRect;
  if not CheckBlock(AConverter) then
    Exit;
  FBox := Block.FBox;
  CalculateMatrix;
  if (Block.Count <> 0) and not IsBadRect(FBox) then
    TransRectCorners(FBox, FMatrix); // don't TransRectCorners for attribs
  if DelayedLoadAttribs then
  begin
    DelayedLoadAttribs := False;
    DoDelayedLoad(AConverter);
  end;
  DoAttribsBox;
  if Layer = nil then
    Layer := AConverter.LayerByName('0');
end;

procedure TsgDXFInsert.OffsetAttribs(const ADelta: TFPoint);
var
  I: Integer;
  vAttrib: TsgDXFAttrib;
begin
  for I := 0 to FAttribs.Count - 1 do
  begin
    vAttrib := FAttribs.List[I];
    vAttrib.Point := OffsetFPoint(vAttrib.Point, ADelta, True);
    if vAttrib.HasSecond then
      vAttrib.Point1 := OffsetFPoint(vAttrib.Point1, ADelta, True);
  end;
end;

function TsgDXFInsert.GetName: string;
var
  vEnt: TsgDXFEntity;
begin
  Result := '';
  if Assigned(Block) then
    if Block.ClassType = TsgLinkObject then
    begin
      case TsgLinkObject(Block).FData.LinkType of
        lodtName:
          Result := TsgLinkObject(Block).Name;
        lodtHandle:
          begin
            vEnt := nil;
            if Assigned(Converter) and (Converter.Counts[csBlockRecords] > 0)
            then
              vEnt := TsgLinkObject(Block)
                .GetObject(Converter.Sections[csBlockRecords]);
            if Assigned(vEnt) then
              Result := vEnt.Name;
          end;
      end;
    end
    else
      Result := Block.Name
end;

function TsgDXFInsert.GetNodeName: string;
begin
  if FSceneElement > 0 then
    Result := GetXMLNameOfSceneElement
  else
    Result := inherited GetNodeName;
end;

class function TsgDXFInsert.GetXMLNameOfSceneElement: string;
begin
  Result := cnstXMLPrefix + cnstSceneElement;
end;

procedure TsgDXFInsert.InitializeMatrix;
begin
  FMatrix := cnstIdentityMat;
end;

function TsgDXFInsert.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  Result := AEntity.EntType = ceAttrib;
  if Result then
    FAttribs.Insert(AIndex, AEntity);
end;

procedure TsgDXFInsert.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
var
  P: PsgCADIterate;
  Saved, SavedBlock: TsgCADIterate;
  SavedMatrix: TFMatrix;
  vConv: TsgDXFConverter;
  vConvsMatrix: PFMatrix;
  vEnt: TsgDXFEntity;
  vEnters, I: Integer;
  vAttdefs: TList;

  procedure ApplyAttribs(AAttdefs: TList);
  var
    I, J: Integer;
    vIsHaveAttdef: Boolean;
    vAttdef: TsgDXFAttdef absolute vEnt;
    vAttrib: TsgDXFAttrib;
  begin
    for I := 0 to FAttribs.Count - 1 do
    begin
      vAttrib := FAttribs.List[I];
      vIsHaveAttdef := False;
      if AAttdefs <> nil then
      begin
        for J := 0 to AAttdefs.Count - 1 do
        begin
          vEnt := TsgDXFEntity(AAttdefs[J]);
          if vAttrib.Tag = vAttdef.Tag then
          begin
            vIsHaveAttdef := True;
            if not vAttdef.Constant then
              vAttdef.FHasChanging := True;
            vAttrib.Invoke(AConverter, Proc, FinishProc);
            Break;
          end;
        end;
      end;
      if not vIsHaveAttdef and (not vAttrib.NotAppear) then
        vAttrib.Invoke(AConverter, Proc, FinishProc);
    end;
  end;

  procedure InitDefParams(APCADIterate: PsgCADIterate);
  begin

    APCADIterate^.Insert := Self;
    APCADIterate^.Color := Color;
    APCADIterate^.XScale := 0.0;
    APCADIterate^.YScale := 0.0;
    if (LineType = nil) or (LineType.Name <> sByBlock) then
      APCADIterate^.LType := Lines;
  end;

begin
  vEnters := Integer(AConverter.AutoInsert and (Block <> nil));
  if vEnters = 0 then
    vEnters := Proc(Self);
  if vEnters = 0 then
    Exit;
  if Assigned(Converter) then
  begin
    New(vConvsMatrix);
    try
      vConv := Converter.GetMainConverter(vConvsMatrix);
      SavedMatrix := vConv { FConverter }.FTransform3D;
      vConv.FTransform3D := FMatXMat(FMatrix, vConvsMatrix^);
    finally
      Dispose(vConvsMatrix);
    end;
  end
  else
    vConv := nil;
  P := AConverter.FParams;
  Saved := P^;
  FOwnerInsert := P.Insert;
  vAttdefs := nil;
  try
    if vEnters = 1 then
    begin
      // Could be changed by attribs
      FillChar(SavedBlock, SizeOf(SavedBlock), 0);
      SavedBlock.DrawMatrix := P.DrawMatrix;
      SavedBlock.Matrix := FMatXMat(FMatrix, P.Matrix);
      // only after calling ApplyAttribs
      SavedBlock.Additional := Integer(IsRotatedFMat(SavedBlock.Matrix));
      SavedBlock.ConvertMatrixCurrentIndertToWCS :=
        FMatXMat(P.ConvertMatrixCurrentIndertToWCS, GetMatrix);
      SavedBlock.LType := Saved.LType;
      InitDefParams(@SavedBlock);
      P^ := SavedBlock;
      vAttdefs := Block.IterateEx(AConverter, Proc, FinishProc);
    end;
    if FAttribs.Count > 0 then
    begin
      P^ := Saved;
      InitDefParams(P);
      ApplyAttribs(vAttdefs);
      if vAttdefs <> nil then
      begin
        P^ := SavedBlock;
        for I := 0 to vAttdefs.Count - 1 do
          TsgDXFEntity(vAttdefs[I]).Invoke(AConverter, Proc, FinishProc);
      end;
    end;
  finally
    vAttdefs.Free;
  end;
  P^ := Saved;
  FOwnerInsert := P.Insert;
  if Assigned(vConv) then
    vConv.FTransform3D := SavedMatrix;
  if Assigned(FinishProc) then
    FinishProc(Self);
end;

function TsgDXFInsert.GetMatrix: TFMatrix;
begin
  Result := FMatrix;
end;

function TsgDXFInsert.GetEntType: TsgCADEntities;
begin
  Result := ceInsert;
end;

function TsgDXFInsert.ExtractParamsFromMatrix2D(var P, S: TFPoint;
  var A: Double): Boolean;
begin
  Result := FMatExtractParams2D(FMatrix, P, S, A);
end;

function TsgDXFInsert.IsInsert: Boolean; // evg
begin
  Result := True;
end;

function TsgDXFInsert.IsOnePixelOptimisationValid: Boolean; // evg
begin
  Result := False;
end;

{$IFDEF SG_BTI}

function TsgDXFInsert.GetExtendedData: PsgExtendedData;
begin
  Result := nil;
end;

function TsgDXFInsert.GetExtendedBlockData: TsgExtendedBlockData;
begin
  Result := nil;
end;

function TsgDXFInsert.GetOwnerConstruction: TsgDXFEntity;
begin
  Result := nil;
end;

procedure TsgDXFInsert.GetArcsParams(var Arcs: TsgArcsParams);
begin
  FillChar(Arcs, SizeOf(Arcs), 0);
end;

procedure TsgDXFInsert.GetPts(var APts: TsgPoints4);
begin
  FillChar(APts, SizeOf(APts), 0);
end;

procedure TsgDXFInsert.GetPtsEx(const AList: TFPointList);
begin
end;

procedure TsgDXFInsert.SetExtendedData(const Value: PsgExtendedData);
begin // do nothing
end;
{$ENDIF}

function TsgDXFInsert.GetExtrusion: TFPoint;
begin
  Result := FExtrusion;
end;

function TsgDXFInsert.GetHasAttribs: Boolean;
begin
  Result := (FAttribs <> nil) and (FAttribs.Count > 0);
end;

function TsgDXFInsert.GetLineWeight: Double;
begin
  Result := FLineWeight;
end;

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

procedure TsgDXFInsert.SetScale(const Value: TFPoint);
var
  vAttrib: TsgDXFAttrib;
  vScaleKoef: TFPoint;
  vHeightKoef: Double;
  I: Integer;

  procedure ApplyAttribPoint(var AAttribPoint: TFPoint);
  begin
    AAttribPoint.X := FPoint.X + (AAttribPoint.X - FPoint.X) * vScaleKoef.X;
    AAttribPoint.Y := FPoint.Y + (AAttribPoint.Y - FPoint.Y) * vScaleKoef.Y;
    AAttribPoint.Z := FPoint.Z + (AAttribPoint.Z - FPoint.Z) * vScaleKoef.Z;
  end;

begin
  if FAttribs.Count > 0 then
  begin
    try
      vScaleKoef.X := Value.X / FScale.X;
      vScaleKoef.Y := Value.Y / FScale.Y;
      vScaleKoef.Z := Value.Z / FScale.Z;
    except
      vScaleKoef := cnstFPointSingle;
    end;
    for I := FAttribs.Count - 1 downto 0 do
    begin
      vAttrib := Attribs[I];
      // Scale Attrib width/height
      vHeightKoef := vAttrib.Height;
      vAttrib.Height := vAttrib.Height * vScaleKoef.Y;
      if vAttrib.Height <> 0 then
        vHeightKoef := vHeightKoef / vAttrib.Height;
      vAttrib.Scale := vAttrib.Scale * vHeightKoef * vScaleKoef.X;
      // Scale Attrib position
      ApplyAttribPoint(vAttrib.FPoint);
      if vAttrib.HasSecond then
        ApplyAttribPoint(vAttrib.FPoint1);
    end;
  end;
  FScale := Value;
end;

function TsgDXFInsert.ToXMLGeoData(const ANode: TsgNode;
  const AMode: TsgXMLModes): Integer;
begin
  Result := cnstXML_OK;
  ANode.AddAttribNV(cnstXMLNames[xmlExtrusion].Name).ValueAsFPoint := Extrusion;
  ANode.AddAttribNV(cnstXMLNames[xmlAngle].Name).ValueAsDouble := Angle;
  ANode.AddAttribNV(cnstXMLNames[xmlFPointScale].Name).ValueAsFPoint := Scale;
end;

function TsgDXFInsert.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  if IsXMLHelp(AMode) then
    ANode.AddAttribNV(cnstXMLNames[xmlBlockName].Name)
  else if Assigned(Block) then
    ANode.AddAttribNV(cnstXMLNames[xmlBlockName].Name).ValueAsStr := Block.Name;
  ToXMLGeoData(ANode, AMode);
end;

procedure TsgDXFInsert.FreeReferences;
var
  vBlock: TsgDXFBlock;
begin
  inherited FreeReferences;
  vBlock := Block;
  if Assigned(vBlock) then
  begin
    if (vBlock.Owner = nil) or (vBlock.Owner = Self) then
      vBlock.Free
    else
      SetBlockRecord(nil); // release ref only
  end;
  FreeAndNil(FAttribs);
end;

function TsgDXFInsert.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlBlockName:
      begin
        if IsHandleStr(ANode.Value) then
          Block := TsgDXFBlock(Converter.Sections[csBlocks].FindEntByHandle
            (ANode.ValueAsHandle))
        else
          Block := Converter.BlockByName(ANode.Value);
      end;
    xmlExtrusion:
      Extrusion := ANode.ValueAsFPoint;
    xmlAngle:
      Angle := ANode.ValueAsDouble;
    xmlFPointScale:
      Scale := ANode.ValueAsFPoint;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

{ TsgCADClipInsert }

constructor TsgCADClipInsert.Create;
begin
  inherited Create;
  FClipBox := BadRect;
end;

procedure TsgCADClipInsert.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgCADClipInsert then
    FClipBox := TsgCADClipInsert(Source).FClipBox;
end;

function TsgCADClipInsert.GetBox: TFRect;
begin
  Result := inherited GetBox;
  if Result.Left < FClipBox.Left then
    Result.Left := FClipBox.Left;
  if Result.Right > FClipBox.Right then
    Result.Right := FClipBox.Right;
  if Result.Top > FClipBox.Top then
    Result.Top := FClipBox.Top;
  if Result.Bottom < FClipBox.Bottom then
    Result.Bottom := FClipBox.Bottom;
  // if Result.Left > Result.Right        then Result.Left := Result.Right;
  // if Result.Bottom > Result.Top        then Result.Bottom := Result.Top;
end;

function TsgCADClipInsert.GetClipBox: TFRect;
begin
  Result := FClipBox;
end;

procedure TsgCADClipInsert.SetClipBox(const Value: TFRect);
begin
  FClipBox := Value;
end;

procedure TsgCADClipInsert.SetPoint(AValue: TFPoint);
var
  Delta: TFPoint;
begin
  Delta := OffsetFPoint(AValue, Point, False);
  inherited SetPoint(AValue);
  FClipBox.TopLeft := OffsetFPoint(FClipBox.TopLeft, Delta, True);
  FClipBox.BottomRight := OffsetFPoint(FClipBox.BottomRight, Delta, True);
end;

{ TsgCADMInsert }

procedure TsgCADMInsert.AssignEntity(Source: TsgDXFEntity);
var
  M: TsgCADMInsert absolute Source;
begin
  inherited AssignEntity(Source);
  if not(Source is TsgCADMInsert) then
    Exit;
  NumCols := M.NumCols;
  NumRows := M.NumRows;
  ColSpacing := M.ColSpacing;
  RowSpacing := M.RowSpacing;
end;

constructor TsgCADMInsert.Create;
begin
  inherited Create;
  FNumCols := 1;
  FNumRows := 1;
end;

function TsgCADMInsert.GetBox: TFRect;
var
  vPoint1, vPoint2, vPointColRow: TFPoint;
begin
  Result := inherited GetBox;
  if not IsBadRect(Result) then
  begin
    vPointColRow := MakeFPoint(ColSpacing * (NumCols - 1),
      RowSpacing * (NumRows - 1), 0);
    vPoint1 := AddFPoint(Result.TopLeft, vPointColRow);
    vPoint2 := AddFPoint(Result.BottomRight, vPointColRow);
    ExpandFRect(Result, vPoint1);
    ExpandFRect(Result, vPoint2);
  end;
end;

function TsgCADMInsert.GetColSpacing: Double;
begin
  Result := FColSpacing;
end;

function TsgCADMInsert.GetNumCols: Integer;
begin
  Result := FNumCols;
end;

function TsgCADMInsert.GetNumRows: Integer;
begin
  Result := FNumRows;
end;

function TsgCADMInsert.GetRowSpacing: Double;
begin
  Result := FRowSpacing;
end;

procedure TsgCADMInsert.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
var
  I, J: Integer;
  P, P0: TFPoint;
begin
  P0 := Point;
  P := P0;
  try
    for I := 0 to NumRows - 1 do
    begin
      P.X := P0.X;
      for J := 0 to NumCols - 1 do
      begin
        Point := P;
        CalculateMatrix;
        inherited Invoke(AConverter, Proc, FinishProc);
        P.X := P.X + ColSpacing;
      end;
      P.Y := P.Y + RowSpacing;
    end;
  finally
    Point := P0;
    CalculateMatrix;
  end;
end;

procedure TsgCADMInsert.SetColSpacing(const Value: Double);
begin
  FColSpacing := Value;
end;

procedure TsgCADMInsert.SetNumCols(const Value: Integer);
begin
  if (Value >= 1) and (Value <= 65535) then
    FNumCols := Value;
end;

procedure TsgCADMInsert.SetNumRows(const Value: Integer);
begin
  if (Value >= 1) and (Value <= 65535) then
    FNumRows := Value;
end;

procedure TsgCADMInsert.SetRowSpacing(const Value: Double);
begin
  FRowSpacing := Value;
end;

function TsgCADMInsert.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlColumnCount].Name).ValueAsInt := NumCols;
  ANode.AddAttribNV(cnstXMLNames[xmlRowCount].Name).ValueAsInt := NumRows;
  ANode.AddAttribNV(cnstXMLNames[xmlColSpacing].Name).ValueAsDouble :=
    ColSpacing;
  ANode.AddAttribNV(cnstXMLNames[xmlRowSpacing].Name).ValueAsDouble :=
    RowSpacing;
end;

{ TsgDXFDimension }

procedure TsgDXFDimension.AssignEntity(Source: TsgDXFEntity);
var
  vDimension: TsgDXFDimension absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFDimension then
  begin
    FAssociated := vDimension.FAssociated;
    FDefPoint := vDimension.FDefPoint;
    Style := vDimension.Style;
    FFlags := vDimension.FFlags;
    FLinDefPoint1 := vDimension.FLinDefPoint1;
    FLinDefPoint2 := vDimension.FLinDefPoint2;
    FMiddlePoint := vDimension.FMiddlePoint;
    FTextOverride := vDimension.FTextOverride;
    FTextRotation := vDimension.FTextRotation;
    if vDimension.Properties <> nil then
      ActualDimStyle.AssignEntity(vDimension.Properties)
    else
      FPropertiesItem.Item := nil;
  end;
end;

function TsgDXFDimension.BeginExtData(const AData: TsgCADExtendedData): Boolean;
begin
  AData.AddString(String_1001, sACADXDataAppName);
  AData.AddString(String_1000, cnstDStyle);
  AData.AddString(String_1002, '{');
  Result := True;
end;

procedure TsgDXFDimension.EndExtData(const AData: TsgCADExtendedData);
begin
  AData.AddString(String_1002, '}');
end;

procedure TsgDXFDimension.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FDimStyleItem);
  FreeAndNil(FPropertiesItem);
end;

function TsgDXFDimension.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  vStyle: TsgDXFDimensionStyle;
  vArrowType: Integer;
  vArrowSize: Double;
  vPropertiesInit: TsgDimNameVals;

  function GetDimStyle(const ANode: TsgNodeSample): TsgDXFDimensionStyle;
  begin
    if IsHandleStr(ANode.Value) then
      Result := TsgDXFDimensionStyle(Converter.Sections[csDimStyles]
        .FindEntByHandle(ANode.ValueAsHandle))
    else
      Result := TsgDXFDimensionStyle(Converter.Sections[csDimStyles]
        .FindEntByName(ANode.Value));
  end;

begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  if (not Assigned(Style)) and Assigned(Converter) then
    Style := Converter.DimensionStyleByName(Converter.HeadVarStruct.DimStyle);
  case AType.ID of
    xmlArrowType:
      begin
        vArrowType := ANode.ValueAsInt;
        if (vArrowType >= Integer(Low(TsgDimArrowType))) and
          (vArrowType <= Integer(High(TsgDimArrowType))) and
          (ArrowType <> vArrowType) then
          ArrowType := vArrowType;
      end;
    xmlArrowSize:
      ArrowSize := ANode.ValueAsDouble;
    xmlDimStyle:
      begin
        vStyle := GetDimStyle(ANode);
        if Assigned(vStyle) then
        begin
          vArrowType := ArrowType;
          vArrowSize := ArrowSize;
          try
            vPropertiesInit := [];
            if Assigned(Properties) then
              vPropertiesInit := Properties.PropertiesInit;
            Style := vStyle;
            ActualDimStyle.SetOwnerStyle(Style);
          finally
            if vnDIMLRBLK in vPropertiesInit then
              ArrowType := vArrowType;
            if vnDIMASZ in vPropertiesInit then
              ArrowSize := vArrowSize;
          end;
        end;
      end;
    xmlProperties:
      begin
        if (ActualDimStyle.OwnerStyle = nil) or
          (ActualDimStyle.PropertiesInit = []) then
          ActualDimStyle.SetOwnerStyle(Style);
        Properties.FromXMLAsProperties(ANode, AResult);
      end;
    xmlDefPoint:
      DefPoint := ANode.ValueAsFPoint;
    xmlLinDefPoint1:
      LinDefPoint1 := ANode.ValueAsFPoint;
    xmlLinDefPoint2:
      LinDefPoint2 := ANode.ValueAsFPoint;
    xmlMiddlePoint:
      MiddlePoint := ANode.ValueAsFPoint;
    xmlArcDefPoint:
      ArcDefPoint := ANode.ValueAsFPoint;
    xmlRadDefPoint:
      RadDefPoint := ANode.ValueAsFPoint;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFDimension.GetPrecision: Integer;
begin
  Result := ActualDimStyle.DIMDEC;
end;

function TsgDXFDimension.GetProperties: TsgDXFDimensionStyle;
begin
  Result := TsgDXFDimensionStyle(FPropertiesItem.Item);
end;

function TsgDXFDimension.GetActualDimStyle: TsgDXFDimensionStyle;
begin
  if FPropertiesItem.Item = nil then
  begin
    FPropertiesItem.Item := TsgDXFDimensionProperties.Create;
    FPropertiesItem.Item.SetConverter(Converter);
    GetProperties.SetOwnerStyle(Self.Style);
  end;
  Result := GetProperties;
end;

function TsgDXFDimension.GetRadDefPoint: TFPoint;
begin
  Result := FRadDefPoint;
end;

procedure TsgDXFDimension.GenerateBlock(const AConverter: TsgDXFConverter);
const
  cnstBlockNameLine = 'sgCLOSEDFILEDLINE';
type
  TsgArrowPos = (arUndefined, arDefault, arTextOut, arArrowOut,
    arArrowAndTextOut);
var
  vCountCrossPoint, vNumLine: Integer;
  vLines: array [0 .. 3] of TsgDXFLine;
  vPointA, vPoint1: TFPoint;
  vPointCross: array [0 .. 1] of TFPoint;
  vAngle, vTextLen, vTextHeight, vTextRot, vTextWidth: Double;
  vTextPoint: TFPoint;
  vDimText: TsgDXFText;
  vName: string;
  vIsShort: Boolean;
  vPointClassify: TsgPointClassify;
  vTextRect: array [0 .. 3] of TFPoint;
  vTextOffset, vArrowSize, vExtLineOffset, vExtLineExt: Double;

  function IsLineCrossed(APointA1, APointA2, APointB1,
    APointB2: PFPoint): Boolean;
  var
    vRes: Double;
  begin
    vRes := (APointA1^.X - APointA2^.X) * (APointB1^.Y - APointB2^.Y) -
      (APointA1^.Y - APointA2^.Y) * (APointB1^.X - APointB2^.X);
    Result := (Abs(vRes) >= fAccuracy);
  end;

  function PointCrossedPerpendicularLine(K, B: TsgFloat;
    const P: TFPoint): TFPoint;
  begin
    Result.X := (-B * K + P.Y * K + P.X) / (1 + K * K);
    Result.Y := K * Result.X + B;
    Result.Z := 0;
  end;

  function PointCrossedPerpendicularLines(const P1, P2, P: TFPoint;
    var ACross: TFPoint): Boolean;
  var
    K, B, DX: Double;
  begin
    DX := P2.X - P1.X;
    Result := Abs(DX) > fAccuracy;
    if Result then
    begin
      K := (P2.Y - P1.Y) / DX;
      B := P1.Y - K * P1.X;
      ACross := PointCrossedPerpendicularLine(K, B, P);
    end;
  end;

  function PointCrossedPerpendicularLinesEx(const P1, P2, P: TFPoint): TFPoint;
  var
    K, B, DX: Double;
  begin
    DX := P2.X - P1.X;
    if Abs(DX) > fAccuracy then
    begin
      K := (P2.Y - P1.Y) / DX;
      B := P1.Y - K * P1.X;
      Result := PointCrossedPerpendicularLine(K, B, P);
    end
    else
    begin
      Result.X := P1.X;
      Result.Y := P.Y;
      Result.Z := 0;
    end;
  end;

  function AngleInterOXandLine(AP1, AP2: PFPoint): Double;
  var
    vDX, vDY, vLen: Double;
  begin
    vDY := AP1^.Y - AP2^.Y;
    vDX := AP1^.X - AP2^.X;
    vLen := DistanceFPoint(AP1^, AP2^);
    if vLen > fAccuracy then
    begin
      Result := sgFunction.sgArcSin(Abs(vDY) / vLen);
      if (vDX < 0) and (vDY > 0) then
        Result := 2 * Pi - Result
      else if (vDX < 0) and (vDY > 0) then
        Result := Pi - Result
      else
        Result := 0;
    end
    else
      Result := 0;
  end;

  function PointCrossedLine(A, B, C, D: PFPoint; var APoint: TFPoint): Boolean;
  var
    denom, R, S: Double;
  begin
    Result := False;
    denom := (B^.X - A^.X) * (D^.Y - C^.Y) - (B^.Y - A^.Y) * (D^.X - C^.X);
    if Abs(denom) > fAccuracy then
    begin
      R := ((A^.Y - C^.Y) * (D^.X - C^.X) - (A^.X - C^.X) *
        (D^.Y - C^.Y)) / denom;
      S := ((A^.Y - C^.Y) * (B^.X - A^.X) - (A^.X - C^.X) *
        (B^.Y - A^.Y)) / denom;
      if (R >= 0.0 - fAccuracy) and (R <= 1.0 + fAccuracy) and
        (S >= 0.0 - fAccuracy) and (S <= 1.0 + fAccuracy) then
      begin
        APoint := MakeFPoint(A^.X + R * (B^.X - A^.X),
          A^.Y + R * (B^.Y - A^.Y), 0);
        Result := True;
      end;
    end;
  end;

  procedure PointsCrossedTextBox(APoint1, APoint2: PFPoint);
  var
    I: Integer;
  begin
    vCountCrossPoint := 0;
    vNumLine := 0;
    for I := 0 to 2 do
    begin
      if PointCrossedLine(APoint1, APoint2, @vTextRect[I], @vTextRect[I + 1],
        vPointCross[vCountCrossPoint]) then
      begin
        case I of
          0:
            vNumLine := vNumLine + 1;
          1:
            vNumLine := vNumLine + 10;
          2:
            vNumLine := vNumLine + 100;
        end;
        Inc(vCountCrossPoint);
      end;
      if vCountCrossPoint > 1 then
        Break;
    end;
    if (vCountCrossPoint < 2) and
      (PointCrossedLine(APoint1, APoint2, @vTextRect[0], @vTextRect[3],
      vPointCross[vCountCrossPoint])) then
    begin
      Inc(vCountCrossPoint);
      vNumLine := vNumLine + 1000;
    end;
  end;

  procedure SetTextString(const AValue: Double);
  begin
    if FTextOverride <> '' then
      vDimText.Text := FTextOverride
    else
      vDimText.Text := sgFunction.DoubleToStrF(AValue * MeasurementsScale,
        Precision);
  end;

  procedure TextLoaded;
  var
    vRot: Double;
    vRotPt: TFPoint;
  begin
    vDimText.Point := vTextPoint;
    vDimText.Rotation := 0;
    vDimText.Loaded(AConverter);
    if Abs(FTextRotation) > fAccuracy then
      vDimText.Rotation := FTextRotation
    else
      vDimText.Rotation := GetTextAlignedRotation(TextAlign, vTextRot);
    vTextWidth := vDimText.FBox.Right - vDimText.FBox.Left;
    vTextHeight := vDimText.FBox.Top - vDimText.FBox.Bottom;
    vTextRect[0] := vDimText.FBox.TopLeft;
    vTextRect[2] := vDimText.FBox.BottomRight;
    if not vDimText.WinFont then
    begin
      vTextRect[0].X := vTextRect[0].X - vTextOffset;
      vTextRect[0].Y := vTextRect[0].Y + vTextOffset;
      vTextRect[2].X := vTextRect[2].X + vTextOffset;
      vTextRect[2].Y := vTextRect[2].Y - vTextOffset;
    end;
    vTextRect[1] := vTextRect[0];
    vTextRect[1].X := vTextRect[2].X;
    vTextRect[3] := vTextRect[2];
    vTextRect[3].X := vTextRect[0].X;
    if ((TextAlign = 1) or (Abs(FTextRotation) > fAccuracy)) and
      (not(IsEqual(vDimText.Rotation, 0) or IsEqual(vDimText.Rotation, 360)))
    then
    begin
      vRot := vDimText.Rotation * fPiDividedBy180;
      vRotPt := sgFunction.MiddleFPoint(vTextRect[0], vTextRect[2]);

      vDimText.Point := RotateAroundFPoint(vTextPoint, vRotPt, False, vRot);
      vDimText.Loaded(AConverter);

      vTextRect[0] := RotateAroundFPoint(vTextRect[0], vRotPt, False, vRot);
      vTextRect[1] := RotateAroundFPoint(vTextRect[1], vRotPt, False, vRot);
      vTextRect[2] := RotateAroundFPoint(vTextRect[2], vRotPt, False, vRot);
      vTextRect[3] := RotateAroundFPoint(vTextRect[3], vRotPt, False, vRot);
    end;
  end;

  procedure AddLines;
  var
    vLineA, vLineB: TsgDXFLine;
    I, vKoefSigned: Integer;
    C, S: Extended;
    A, X, Y, K, B, vMinX, vMinY, vMaxX, vMaxY: Double;
    vAngle, vDistance: Double;
    vTypePosArrow: TsgArrowPos;

    procedure MinMax;
    var
      I: Integer;
    begin
      vMinX := vLines[0].Point.X;
      vMinY := vMinX;
      vMaxX := vLines[0].Point.Y;
      vMaxY := vMaxX;
      for I := 0 to 3 do
      begin
        if vMaxX < vLines[I].Point.X then
          vMaxX := vLines[I].Point.X
        else if vMinX > vLines[I].Point.X then
          vMinX := vLines[I].Point.X;
        if vMaxY < vLines[I].Point.Y then
          vMaxY := vLines[I].Point.Y
        else if vMinY > vLines[I].Point.Y then
          vMinY := vLines[I].Point.Y;
      end;
    end;

    function IsPointInBox(APoint: PFPoint): Boolean;
    begin
      Result := ((APoint^.X >= vMinX) and (APoint^.Y >= vMinY) and
        (APoint^.X <= vMaxX) and (APoint^.Y <= vMaxY));
    end;

    procedure MakeRemoval(AMakeLineB: Boolean);
    var
      vDX, vDY, vLen, vLen1, vLen2: Double;
      vPoint1, vPoint2, vPoint: TFPoint;
      vVisible: Boolean;
      procedure SetPoints(const AL1, AL2: TsgDXFLine);
      begin
        vPoint1 := AL1.Point;
        vPoint2 := AL2.Point;
        vVisible := AL2.Visibility;
{$IFDEF SG_BTI_TEST}
        if AMakeLineB and (not AL1.Visibility) then
          AL2.Visibility := False;
{$ENDIF}
      end;

    begin
      vTextRot := 0;
      if FFlags < 128 then
        vPoint := FDefPoint
      else
        vPoint := FMiddlePoint;
      vLen1 := DistanceFPoint(vPoint, vLines[2].Point);
      vLen2 := DistanceFPoint(vPoint, vLines[3].Point);
      if vLen1 > vLen2 then
        SetPoints(vLines[2], vLines[3])
      else
        SetPoints(vLines[3], vLines[2]);
      vLineA := TsgDXFLine.Create;
      AConverter.DoCreate(vLineA);
      vLineA.ColorCAD := cnstColorCADByBlock;
      vLineA.Point := vPoint2;
      vLineA.Point1 := cnstFPointZero;
      vDX := vPoint1.X - vPoint2.X;
      vDY := vPoint1.Y - vPoint2.Y;
      if Abs(vDX) < fAccuracy then
      begin
        vLen := DistanceFPoint(vPoint1, vPoint2);
        if vLen > fAccuracy then
          vAngle := sgFunction.sgArcSin(Abs(vDY / vLen))
        else
          vAngle := 0;
      end
      else
        vAngle := ArcTan(Abs(vDY / vDX));
      SinCos(vAngle, S, C);
      if vPoint2.X > vPoint1.X then
        vKoefSigned := 1
      else
        vKoefSigned := -1;
      if FFlags <> 129 then
      begin
        if AMakeLineB then
        begin
          vLineA.FPoint1.X := vLineA.FPoint.X + vKoefSigned * C * vArrowSize;
          if vPoint2.Y > vPoint1.Y then
            vLineA.FPoint1.Y := vLineA.FPoint.Y + S * vArrowSize
          else
            vLineA.FPoint1.Y := vLineA.FPoint.Y - S * vArrowSize;
        end
        else
        begin
          vLineA.FPoint1.X := vLineA.FPoint.X + vKoefSigned * C *
            (ArrowSize * 2);
          if vPoint2.Y > vPoint1.Y then
            vLineA.FPoint1.Y := vLineA.FPoint.Y + S * (vArrowSize * 2)
          else
            vLineA.FPoint1.Y := vLineA.FPoint.Y - S * (vArrowSize * 2);
        end;
        if vAngle > (Pi * 15 / 180) then
        begin
          vLineB := TsgDXFLine.Create;
          AConverter.DoCreate(vLineB);
          vLineB.ColorCAD := cnstColorCADByBlock;
          vLineB.Point := vLineA.Point1;
          vLineB.FPoint1.Z := 0;
          vLineB.FPoint1.Y := vLineB.FPoint.Y;
          vLineB.FPoint1.X := vLineA.FPoint1.X + vKoefSigned * vArrowSize;
          vTextPoint.Y := vLineB.FPoint1.Y;
          vTextPoint.X := vLineB.FPoint1.X + vKoefSigned * vTextOffset;
          if vTextPoint.X < vLineB.Point.X then
            vTextPoint.X := vTextPoint.X - vTextWidth;
          AConverter.Loads(vLineB);
          vLineB.Visibility := vVisible;
          Block.AddEntity(vLineB);
        end
        else
        begin
          vTextPoint := vLineA.Point1;
          vTextPoint.X := vLineA.FPoint1.X + vKoefSigned * vTextOffset;
        end;
      end
      else
      begin
        vLineB := TsgDXFLine.Create;
        AConverter.DoCreate(vLineB);
        vLineB.ColorCAD := cnstColorCADByBlock;
        vLineB.Point := FMiddlePoint;
        if FMiddlePoint.X < vPoint2.X then
          vKoefSigned := 1
        else
          vKoefSigned := -1;
        vLineB.FPoint.X := vLineB.FPoint.X + vKoefSigned *
          (vTextOffset + vTextWidth * 0.5);
        vLineB.FPoint1.Y := vLineB.FPoint.Y;
        if vAngle < (Pi * 15 / 180) then
        begin
          vDX := vTextWidth * 0.5;
          vLineA.FPoint1 := FMiddlePoint;
          if (DistanceFPoint(vLineA.FPoint, vLineA.FPoint1) >
            (vArrowSize + vTextOffset)) then
          begin
            if (vPoint2.X > vPoint1.X) then
              vLineA.FPoint1.X := vLineA.FPoint1.X - vDX
            else
              vLineA.FPoint1.X := vLineA.FPoint1.X + vDX;
          end;
          if vPoint2.Y > vPoint1.Y then
            vLineA.FPoint1.Y := vLineA.FPoint1.Y - S *
              (vArrowSize + Integer(AMakeLineB) * vArrowSize)
          else
            vLineA.FPoint1.Y := vLineA.FPoint1.Y + S *
              (vArrowSize + Integer(AMakeLineB) * vArrowSize);
          vLineB.Point := vLineA.Point;
          vLineB.Point1 := vLineA.Point;
          vTextPoint := vLineA.Point1;
          if vLineA.FPoint1.X > vLineA.FPoint.X then
            vTextPoint.X := vLineA.FPoint1.X - vKoefSigned * vArrowSize
          else
            vTextPoint.X := vLineA.FPoint1.X - vKoefSigned * vTextOffset - vDX;
        end
        else
        begin
          vLineB.FPoint1.X := (vLineB.FPoint1.Y - vPoint1.Y) *
            (vPoint2.X - vPoint1.X) / (vPoint2.Y - vPoint1.Y) + vPoint1.X;
          vLineA.Point1 := vLineB.Point1;
          vLineB.FPoint.X := vLineB.FPoint1.X - vKoefSigned * vArrowSize;
          vTextPoint := vLineB.FPoint; // FMiddlePoint;
          if vLineB.FPoint.X > vLineB.FPoint1.X then
            vTextPoint.X := vTextPoint.X + vTextOffset
          else
            vTextPoint.X := vTextPoint.X - (vTextOffset + vTextWidth);
        end;
        AConverter.Loads(vLineB);
        vLineB.Visibility := vVisible;
        Block.AddEntity(vLineB);
      end;
      AConverter.Loads(vLineA);
      vLineA.Visibility := vVisible;
      Block.AddEntity(vLineA);
      vTextPoint.Y := vTextPoint.Y - vTextHeight * 0.5;
    end;

    procedure SetLinesProps;
    begin
      vLines[2].Visibility := not DIMSD1;
      vLines[3].Visibility := not DIMSD2;
      vLines[0].Visibility := not DIMSE1;
      vLines[1].Visibility := not DIMSE2;

      vLines[2].ColorCAD := DIMCLRD;
      vLines[3].ColorCAD := vLines[2].ColorCAD;
      vLines[0].ColorCAD := DIMCLRE;
      vLines[1].ColorCAD := vLines[0].ColorCAD;

      vLines[2].LineWeight := DIMLWD;
      vLines[3].LineWeight := vLines[2].LineWeight;
      vLines[0].LineWeight := DIMLWE;
      vLines[1].LineWeight := vLines[0].LineWeight;
    end;

    procedure MakeArrowPos;
    var
      vLen1, vLen2: Double;

      procedure MakePos(const ATypePosArrow: TsgArrowPos);
      var
        vIndex: Boolean;
      begin
        SetLinesProps;
        case ATypePosArrow of
          arDefault: // <--text-->
            begin
              vIndex := DistanceFPoint(vLines[2].FPoint, vPointCross[0]) <
                DistanceFPoint(vLines[2].FPoint, vPointCross[1]);
              vLines[2].Point1 := vPointCross[Integer(not vIndex)];
              vLines[3].Point1 := vPointCross[Integer(vIndex)];
            end;
          arTextOut: // <---->--text
            begin
              MakeRemoval(True);
              vLines[2].Point1 := vLines[3].Point;
              vLines[3].Point1 := vLines[2].Point;
            end;
          arArrowOut: // ->text<-
            begin
              vIsShort := True;
              vPoint1 := vLines[2].Point;
              vLines[2].Point := vLines[3].Point;
              vLines[3].Point := vPoint1;
              vLines[2].Point1 := vLines[2].Point;
              vLines[3].Point1 := vLines[3].Point;
            end;
          arArrowAndTextOut: // ->  <---text
            begin
              vIsShort := True;
              vPoint1 := vLines[2].Point;
              vLines[2].Point := vLines[3].Point;
              vLines[3].Point := vPoint1;
              vLines[2].Point1 := vLines[2].Point;
              vLines[3].Point1 := vLines[3].Point;
              if ((X - (vTextLen + 2 * vTextOffset)) < vTextOffset) and
                (FFlags <> 129) then
                MakeRemoval(False);
            end;
        end;
      end;

      function IsAngleByTypePosArrowMode2(const AAngle: Double): Boolean;
      begin
        Result := ((AAngle >= 60) and (AAngle <= 80)) or
          ((AAngle >= 100) and (AAngle <= 120)) or
          ((AAngle >= 240) and (AAngle <= 260)) or
          ((AAngle >= 180) and (AAngle <= 200));
      end;

    begin
      vTypePosArrow := arUndefined;
      vIsShort := False;
      if FFlags >= 128 then
        vTextPoint := FMiddlePoint
      else
        vTextPoint := MakeFPoint((vLines[2].FPoint.X + vLines[3].FPoint.X) / 2,
          (vLines[2].FPoint.Y + vLines[3].FPoint.Y) / 2, 0);

      vTextPoint.X := vTextPoint.X - vTextWidth * 0.5;
      Y := vLines[3].Point.Y - vLines[2].Point.Y;
      vTextPoint.Y := vTextPoint.Y - vTextHeight * 0.5;
      if FFlags > 127 then
        vTextPoint.Y := vTextPoint.Y + vTextOffset *
          (1 + 0.4 * Integer(not vDimText.WinFont));

      vTextRot := GetAngleByPoints(vLines[3].FPoint, vLines[2].FPoint, False);
      TextLoaded;
      PointsCrossedTextBox(@vLines[2].FPoint, @vLines[3].FPoint);

      if vCountCrossPoint < 2 then
      begin
        vPointCross[0] := vLines[3].Point;
        vPointCross[1] := vLines[2].Point;
        vTextLen := vTextWidth;
        // DistanceFP(@vText.FBox.TopLeft, @vText.FBox.BottomRight);
      end
      else
      begin
        vTextLen := DistanceFPoint(vPointCross[0], vPointCross[1]);
        if (Y > 0) and (vNumLine <> 1010) then
          SwapFPoints(vPointCross[0], vPointCross[1])
        else
        begin
          if (FFlags = 0) and (vLines[2].Point.X < vLines[3].Point.X) and
            (vPointCross[0].X > vPointCross[1].X) then
            SwapFPoints(vPointCross[0], vPointCross[1]);
        end;
      end;
      X := DistanceFPoint(vLines[2].Point, vLines[3].Point);
      if FFlags < 129 then
      begin
        if (X > (vTextLen + 2 * vArrowSize + 2 * 2 * vTextOffset)) then
          vTypePosArrow := arDefault
        else
        begin
          if (X >= (4 * vArrowSize)) then
          begin
            if X > 1 then
              vTypePosArrow := arArrowOut
            else
            begin
              if IsAngleByTypePosArrowMode2
                (Degree(AngleInterOXandLine(@vLines[2].FPoint,
                @vLines[3].FPoint))) then
                vTypePosArrow := arArrowOut
              else
              begin
                if X > (3 * vArrowSize) then
                  vTypePosArrow := arTextOut
                else
                  vTypePosArrow := arArrowAndTextOut
              end;
            end;
          end
          else
          begin
            if X > (3 * vArrowSize) then
              vTypePosArrow := arTextOut
            else
              vTypePosArrow := arArrowAndTextOut
          end;
        end;
      end
      else
      begin
        vLen1 := DistanceFPoint(vLines[2].Point, vPointCross[0]);
        vLen2 := DistanceFPoint(vLines[3].Point, vPointCross[1]);
        MinMax;
        if IsPointInBox(@vPointCross[0]) and IsPointInBox(@vPointCross[1]) and
          (vCountCrossPoint > 1) then
        begin
          if (vLen1 > vArrowSize) and (vLen2 > vArrowSize) then
            vTypePosArrow := arDefault
          else
            vTypePosArrow := arArrowOut;
        end
        else
        begin
          if (vCountCrossPoint > 1) or ((FMiddlePoint.X > vLines[2].Point.X) and
            (FMiddlePoint.X < vLines[3].Point.X)) or
            ((FMiddlePoint.X < vLines[2].Point.X) and
            (FMiddlePoint.X > vLines[3].Point.X)) then
            vTypePosArrow := arArrowAndTextOut
          else
          begin
            if X > (3 * vArrowSize) then
              vTypePosArrow := arTextOut
            else
              vTypePosArrow := arArrowAndTextOut;
          end
        end;
      end;
      if (FFlags = 128) and (vTypePosArrow = arDefault) then
      begin
        if ((vTextPoint.X > vLines[2].Point.X) and
          (vTextPoint.X < vLines[3].Point.X)) or
          ((vTextPoint.X < vLines[2].Point.X) and
          (vTextPoint.X > vLines[3].Point.X)) then
          vTypePosArrow := arDefault
        else
          vTypePosArrow := arTextOut;
      end;
      MakePos(vTypePosArrow);
    end;

    procedure MakeOffsetByDimensionStyle(AFirst, ALast: Integer;
      ALine: TsgDXFLine);
    var
      I: Integer;
    begin
      A := DistanceFPoint(ALine.FPoint1, ALine.FPoint);
      if A > fAccuracy then
        vAngle := (ALine.FPoint1.Y - ALine.FPoint.Y) / A
      else
        vAngle := 1;
      vAngle := sgFunction.sgArcSin(vAngle);
      SinCos(vAngle, S, C);
      for I := AFirst to ALast do
      begin
        if vLines[I].FPoint.Y > vLines[I].FPoint1.Y then
        begin
          vLines[I].FPoint.Y := vLines[I].FPoint.Y + S * vExtLineOffset;
          vLines[I].FPoint1.Y := vLines[I].FPoint1.Y + S * vExtLineExt;
        end
        else
        begin
          vLines[I].FPoint.Y := vLines[I].FPoint.Y + S * vExtLineOffset;
          vLines[I].FPoint1.Y := vLines[I].FPoint1.Y + S * vExtLineExt;
        end;
        if vLines[I].FPoint.X > vLines[I].FPoint1.X then
        begin
          vLines[I].FPoint.X := vLines[I].FPoint.X - C * vExtLineOffset;
          vLines[I].FPoint1.X := vLines[I].FPoint1.X - C * vExtLineExt;
        end
        else
        begin
          vLines[I].FPoint.X := vLines[I].FPoint.X + C * vExtLineOffset;
          vLines[I].FPoint1.X := vLines[I].FPoint1.X + C * vExtLineExt;
        end;
      end;
    end;

    procedure TranslationLines;
    var
      K, B, DX: Double;
    begin
      DX := vLines[1].FPoint1.X - vLines[0].FPoint1.X;
      if Abs(DX) > fAccuracy then
      begin
        K := (vLines[1].FPoint1.Y - vLines[0].FPoint1.Y) / DX;
        B := FMiddlePoint.Y - K * FMiddlePoint.X;
        vLines[0].FPoint1 := PointCrossedPerpendicularLine(K, B,
          vLines[0].FPoint1);
        vLines[1].FPoint1 := PointCrossedPerpendicularLine(K, B,
          vLines[1].FPoint1);
      end
      else
      begin
        vLines[0].FPoint1.X := FMiddlePoint.X;
        vLines[1].FPoint1.X := FMiddlePoint.X;
      end;
    end;

    procedure CorrectTextPos;
    var
      I, vMode: Integer;
      vCrossPts: array [0 .. 3] of TFPoint;
      vActLine: TsgLine;
      vTestTextPoint: TFPoint;
      vPt: PFPoint;
      vMx, vMy, vMax: Double;

      procedure InitCrossPts(const AP0, AP1: TFPoint;
        const ABoxPts: array of TFPoint; var ACrossPts: array of TFPoint);
      var
        I: Integer;
        vDX, K, B, X, Y: Double;
      begin
        for I := 0 to 3 do
        begin
          vDX := AP1.X - AP0.X;
          if Abs(vDX) > fAccuracy then
          begin
            K := (AP1.Y - AP0.Y) / vDX;
            B := AP0.Y - K * AP0.X;
            X := (-B * K + ABoxPts[I].Y * K + ABoxPts[I].X) / (1 + K * K);
            Y := K * X + B;
          end
          else
          begin
            X := AP1.X;
            Y := vTextRect[I].Y;
          end;
          ACrossPts[I] := MakeFPoint(X, Y, 0);
        end;
      end;

      function GetDistance(const AP0, AP1: TFPoint;
        const ABoxPts: array of TFPoint;
        var ACrossPts: array of TFPoint): Double;
      var
        I: Integer;
        vD: Double;
      begin
        Result := -MaxDouble;
        InitCrossPts(AP0, AP1, ABoxPts, ACrossPts);
        for I := 0 to 3 do
        begin
          vD := Sqrt(Sqr(ABoxPts[I].X - ACrossPts[I].X) +
            Sqr(ABoxPts[I].Y - ACrossPts[I].Y));
          if vD > Result then
            Result := vD;
        end;
      end;

      function GetTextPosMode(const AP1, AP2, AP: TFPoint): Integer;
      var
        vDX, vDelta: Double;
      begin
        vDX := AP2.X - AP1.X;
        if Abs(vDX) > fAccuracy then
          vDelta := AP.Y - ((AP.X - AP1.X) * (AP2.Y - AP1.Y) / vDX + AP1.Y)
        else
          vDelta := AP1.X - AP.X;
        if vDelta > fAccuracy then
          Result := 1
        else if vDelta < -fAccuracy then
          Result := -1
        else
          Result := 1;
      end;

    begin
      if TextPosVert in [pvCenter, pvJIS] then
        Exit;
      case vTypePosArrow of
        arDefault, arArrowOut:
          begin
            if IsEqualFPoints(vLines[0].FPoint, vLines[0].FPoint1) then
              if IsEqualFPoints(vLines[1].FPoint, vLines[1].FPoint1) then
                vAngle := GetAngleByPoints(vLines[2].FPoint, vLines[2].FPoint1,
                  True) - Pi * 0.5
              else
                vAngle := GetAngleByPoints(vLines[1].FPoint,
                  vLines[1].FPoint1, True)
            else
              vAngle := GetAngleByPoints(vLines[0].FPoint,
                vLines[0].FPoint1, True);
            SinCos(vAngle, S, C);
            if IsEqualFPoints(vLines[2].FPoint, vLines[2].FPoint1) then
            begin
              if IsEqualFPoints(vLines[3].FPoint, vLines[3].FPoint1) then
              begin
                vActLine.Point1 := vLines[0].FPoint1;
                vActLine.Point2 := vLines[1].FPoint1;
              end
              else
              begin
                vActLine.Point1 := vLines[3].Point;
                vActLine.Point2 := vLines[3].Point1;
              end;
            end
            else
            begin
              vActLine.Point1 := vLines[2].Point;
              vActLine.Point2 := vLines[2].Point1;
            end;
            case TextPosVert of
              pvAbove:
                begin
                  vDistance := DistanceFPoint(vActLine.Point1, vActLine.Point2);
                  if vDistance <= fAccuracy then
                    vDistance := 1024;
                  vTestTextPoint := AddFPoint(vTextPoint,
                    MakeFPoint(vDistance * C, vDistance * S, 0));
                  vMode := GetTextPosMode(vActLine.Point1, vActLine.Point2,
                    vTestTextPoint);
                end;
            else
              // pvOutSide:  vMode := 1;
              vMode := 1;
            end;
            TextLoaded;
            vDistance := GetDistance(vActLine.Point1, vActLine.Point2,
              vTextRect, vCrossPts);
            if vDistance > -1 then
            begin
              vTextPoint.X := vTextPoint.X + vMode * vDistance * C;
              vTextPoint.Y := vTextPoint.Y + vMode * vDistance * S;
              if vTypePosArrow = arDefault then
              begin
                vLines[2].FPoint1 := vLines[3].FPoint;
                vLines[3].FPoint1 := vLines[3].FPoint;
              end;
            end;
          end;
        arTextOut, arArrowAndTextOut:
          begin
            if vLineA <> nil then
            begin
              case TextPosVert of
                pvAbove:
                  begin
                    if vLineB <> nil then
                      vMode := -GetTextPosMode(vLineB.Point, vLineB.Point1,
                        vTextPoint)
                    else
                      vMode := -GetTextPosMode(vLineA.Point, vLineA.Point1,
                        vTextPoint);
                  end;
              else
                vMode := GetTextPosMode(vLineA.Point, vLineA.Point1, DefPoint);
              end;
              TextLoaded;
              if vLineB <> nil then
              begin
                vDistance := GetDistance(vLineB.FPoint, vLineB.FPoint1,
                  vTextRect, vCrossPts);
                if (vLineA <> nil) and (vDistance > -1) then
                begin
                  vTextPoint.Y := vTextPoint.Y + vMode *
                    (vDistance + vTextOffset);
                  if IsEqualFPoints(vLineA.FPoint, vLineB.Point) or
                    IsEqualFPoints(vLineA.FPoint1, vLineB.Point) then
                    vPt := @vLineB.FPoint1
                  else
                    vPt := @vLineB.FPoint;
                  if Abs(vPt^.X - vDimText.FBox.Left) >
                    Abs(vPt^.X - vDimText.FBox.Right) then
                    vPt^.X := vDimText.FBox.Left
                  else
                    vPt^.X := vDimText.FBox.Right;
                end;
              end
              else
              begin
                vDistance := GetDistance(vLineA.FPoint, vLineA.FPoint1,
                  vTextRect, vCrossPts);
                if vDistance > -1 then
                begin
                  vTextPoint.Y := vTextPoint.Y + vMode *
                    (vDistance + vTextOffset);
                  TextLoaded;
                  InitCrossPts(vLineA.FPoint, vLineA.FPoint1, vTextRect,
                    vCrossPts);
                  vMx := (vLineA.FPoint.X + vLineA.FPoint1.X) * 0.5;
                  vMy := (vLineA.FPoint.Y + vLineA.FPoint1.Y) * 0.5;
                  vMax := -MaxDouble;
                  vPt := @cnstFPointZero;
                  for I := 0 to 3 do
                  begin
                    vDistance :=
                      Sqrt(Sqr(vCrossPts[I].X - vMx) +
                      Sqr(vCrossPts[I].Y - vMy));
                    if vMax < vDistance then
                    begin
                      vPt := @vCrossPts[I];
                      vMax := vDistance;
                    end;
                  end;
                  if DistanceFPoint(vLineA.FPoint, vPt^) <
                    DistanceFPoint(vLineA.FPoint1, vPt^) then
                    vLineA.FPoint := vPt^
                  else
                    vLineA.FPoint1 := vPt^;
                end;
              end;
            end;
          end;
      end;
    end;

  begin
    vLineA := nil;
    vLineB := nil;
    for I := 0 to 3 do
    begin
      vLines[I] := TsgDXFLine.Create;
      vLines[I].ColorCAD := cnstColorCADByBlock;
      vLines[I].Point := cnstFPointZero;
      vLines[I].Point1 := cnstFPointZero;
      AConverter.DoCreate(vLines[I]);
    end;
    vLines[0].Point := FLinDefPoint2;
    vLines[0].Point1 := FDefPoint;
    vLines[1].Point := FLinDefPoint1;
    C := DistanceFPoint(FDefPoint, FLinDefPoint2);
    if C > fAccuracy then
    begin
      vDistance := DistanceFPoint(vLines[0].Point, vLines[0].Point1);
      vAngle := GetAngleByPoints(vLines[0].Point, vLines[0].Point1, True);
      SinCos(vAngle, S, C);
      vPointA.X := vLines[1].Point.X + C * vDistance;
      vPointA.Y := vLines[1].Point.Y + S * vDistance;
      vPointA.Z := 0;
      vLines[1].FPoint1 := PointCrossedPerpendicularLinesEx(FLinDefPoint1,
        vPointA, FDefPoint);
      vLines[0].FPoint.X := vLines[0].FPoint.X + C * vExtLineOffset;
      vLines[0].FPoint.Y := vLines[0].FPoint.Y + S * vExtLineOffset;
      vLines[1].FPoint.X := vLines[1].FPoint.X + C * vExtLineOffset;
      vLines[1].FPoint.Y := vLines[1].FPoint.Y + S * vExtLineOffset;
      if (FFlags >= 128) then
      begin
        Y := FDefPoint.Y - FLinDefPoint2.Y;
        if ((Y < 0) and ((FMiddlePoint.X - FDefPoint.X) < 0)) or (Y > 0) then
          TranslationLines;
      end;
      vLines[2].FPoint := vLines[0].FPoint1;
      vLines[3].FPoint := vLines[1].FPoint1;
      vLines[2].FPoint.X := vLines[2].FPoint.X - C * vExtLineExt;
      vLines[2].FPoint.Y := vLines[2].FPoint.Y - S * vExtLineExt;
      vLines[3].FPoint.X := vLines[3].FPoint.X - C * vExtLineExt;
      vLines[3].FPoint.Y := vLines[3].FPoint.Y - S * vExtLineExt;
    end
    else
    begin
      if FFlags = 129 then
      begin
        X := (FLinDefPoint2.X - FLinDefPoint1.X);
        if Abs(X) > fAccuracy then
        begin
          K := (FLinDefPoint2.Y - FLinDefPoint1.Y) / X;
          B := FMiddlePoint.Y - FMiddlePoint.X * K;
          vLines[0].FPoint1 := PointCrossedPerpendicularLine(K, B,
            FLinDefPoint2);
          vLines[1].FPoint1 := PointCrossedPerpendicularLine(K, B,
            FLinDefPoint1);
        end
        else
        begin
          vLines[0].FPoint1.Y := FLinDefPoint2.Y;
          vLines[0].FPoint1.X := FMiddlePoint.X;
          vLines[1].FPoint1.Y := FLinDefPoint1.Y;
          vLines[1].FPoint1.X := FMiddlePoint.X;
        end;
        vTextPoint := FMiddlePoint;
        vTextPoint.X := vTextPoint.X - vTextWidth * 0.5;
        vTextPoint.Y := vTextPoint.Y - vTextHeight * 0.5;
        vPointCross[0] := MakeFPoint(vDimText.Box.Left, vDimText.Box.Bottom, 0);
        vPointCross[1] := MakeFPoint(vDimText.Box.Right,
          vDimText.Box.Bottom, 0);
        if vLines[0].FPoint1.X > vLines[1].FPoint1.X then
        begin
          vMinX := vLines[1].FPoint1.X;
          vMaxX := vLines[0].FPoint1.X;
        end
        else
        begin
          vMinX := vLines[0].FPoint1.X;
          vMaxX := vLines[1].FPoint1.X;
        end;
        if vLines[0].FPoint1.Y > vLines[1].FPoint1.Y then
        begin
          vMinY := vLines[1].FPoint1.Y;
          vMaxY := vLines[0].FPoint1.Y;
        end
        else
        begin
          vMinY := vLines[0].FPoint1.Y;
          vMaxY := vLines[1].FPoint1.Y;
        end;
        if (not IsPointInBox(@FMiddlePoint)) and
          (IsLineCrossed(@vPointCross[0], @vPointCross[1], @vLines[0].FPoint,
          @vLines[1].FPoint)) then
        begin
          A := DistanceFPoint(vLines[1].FPoint1, vLines[1].FPoint);
          X := vTextWidth; // - cnstStyleTextOffset;
          if (FMiddlePoint.X < FDefPoint.X) and (FMiddlePoint.Y < FDefPoint.Y)
          then
            A := fAccuracy;
          if A > fAccuracy then
          begin
            vAngle := (vLines[1].FPoint.Y - vLines[1].FPoint1.Y) / A;
            vAngle := sgFunction.sgArcSin(vAngle);
            if (Abs(vLines[1].FPoint1.X - vLines[1].FPoint.X) > 0.2) then
              Y := Abs(X * Tan(vAngle))
            else
            begin
              X := 0;
              Y := 0;
            end
          end
          else
          begin
            X := 0;
            Y := 0;
          end;
          if vLines[0].FPoint1.X < vLines[1].FPoint1.X then
            vAngle := AngleInterOXandLine(@vLines[0].FPoint1,
              @vLines[1].FPoint1)
          else
            vAngle := AngleInterOXandLine(@vLines[1].FPoint1,
              @vLines[0].FPoint1);
          if vAngle > 2 * Pi then
            vAngle := vAngle - 2 * Pi;
          for I := 0 to 1 do
          begin
            if ((vAngle >= Pi / 2) and (vAngle <= Pi)) or
              ((vAngle >= 1.5 * Pi) and (vAngle <= 2 * Pi)) then
            begin
              if (FMiddlePoint.X > FDefPoint.X) and
                (FMiddlePoint.Y < FDefPoint.Y) then
                vLines[I].FPoint1.X := vLines[I].FPoint1.X - X
              else
                vLines[I].FPoint1.X := vLines[I].FPoint1.X + X;
            end
            else
              vLines[I].FPoint1.X := vLines[I].FPoint1.X - X;

            if FMiddlePoint.Y < FDefPoint.Y then
              vLines[I].FPoint1.Y := vLines[I].FPoint1.Y - Y
            else
              vLines[I].FPoint1.Y := vLines[I].FPoint1.Y + Y;
          end
        end;
        vLines[3].Point := vLines[1].FPoint1;
        vLines[2].Point := vLines[0].FPoint1;
        MakeOffsetByDimensionStyle(0, 1, vLines[1]);
      end
      else
      begin
        vPointClassify := PointClassify(FMiddlePoint, FLinDefPoint1,
          FLinDefPoint2);
        if (FFlags = 0) and ((vPointClassify = pcLEFT) or
          (vPointClassify = pcRIGHT)) then
        begin
          if not PointCrossedPerpendicularLines(FDefPoint, FMiddlePoint,
            FLinDefPoint1, FLinDefPoint2) then
            FLinDefPoint2 := FLinDefPoint1;
          vTextPoint := FMiddlePoint;
          SetTextString(DistanceFPoint(FDefPoint, FLinDefPoint2));
          vDimText.Loaded(AConverter);
          vTextPoint.X := vTextPoint.X - vTextWidth * 0.5;
          vTextPoint.Y := vTextPoint.Y - vTextHeight * 0.5;
          vDimText.Loaded(AConverter);
          vLines[0].Point1 := vLines[0].Point;
          vLines[1].Point := FLinDefPoint1;
          vLines[1].Point1 := FLinDefPoint2;
          MakeOffsetByDimensionStyle(1, 1, vLines[1]);
          vLines[2].Point := FLinDefPoint2;
          vLines[2].Point1 := FDefPoint;
          vLines[3].Point := FDefPoint;
          vLines[3].Point1 := FLinDefPoint2;
        end
        else
        begin
          vLines[1].FPoint1 := vLines[1].FPoint;
          vLines[0].FPoint1 := vLines[0].FPoint;
          vLines[3].Point := vLines[1].FPoint1;
          vLines[2].Point := vLines[0].FPoint1;
        end;
      end;
    end;
    MakeArrowPos;
    if TextPosVert <> pvCenter then
      CorrectTextPos;
    for I := 0 to 3 do
    begin
      AConverter.Loads(vLines[I]);
      Block.AddEntity(vLines[I]);
    end;
    if FFlags = 128 then
      SetTextString(DistanceFPoint(vLines[2].Point, vLines[3].Point));
    TextLoaded;
    Block.AddEntity(vDimText);
  end;

  procedure AddPoint;
  var
    vPoint: TsgDXFPoint;
    vPDMode: Integer;
  begin
    vPDMode := AConverter.HeadVarStruct.PointDisplayMode;
    try
      AConverter.FHeadVarStruct.PointDisplayMode := 0;
      vPoint := TsgDXFPoint.Create;
      AConverter.DoCreate(vPoint);
      vPoint.FPoint.X := FLinDefPoint2.X;
      vPoint.FPoint.Y := FLinDefPoint2.Y;
      vPoint.FPoint.Z := FLinDefPoint2.Z;
      vPoint.ColorCAD := cnstColorCADByBlock;
      vPoint.Layer := AConverter.LayerByName(sLayerDefPoints);
      vPoint.Layer.IsPlotting := False;
      AConverter.Loads(vPoint);
      Block.AddEntity(vPoint);
      vPoint := TsgDXFPoint.Create;
      AConverter.DoCreate(vPoint);
      vPoint.FPoint.X := FLinDefPoint1.X;
      vPoint.FPoint.Y := FLinDefPoint1.Y;
      vPoint.FPoint.Z := FLinDefPoint1.Z;
      vPoint.ColorCAD := cnstColorCADByBlock;
      vPoint.Layer := AConverter.LayerByName(sLayerDefPoints);
      AConverter.Loads(vPoint);
      Block.AddEntity(vPoint);
    finally
      AConverter.FHeadVarStruct.PointDisplayMode := vPDMode;
    end;
  end;

  procedure AddSolid;
  var
    vInsert: TsgDXFInsert;
    vPoint: array [0 .. 1] of TFPoint;
    vVisible: array [0 .. 1] of Boolean;
    vI1, vI2: Integer;
    vLen, vDX, vDY: Double;
    vRotPt: Boolean;

    procedure SetBlock(const AIns: TsgDXFInsert;
      const ArrowType: TsgDimArrowType);
    begin
      AIns.Block := AConverter.BlockByName
        (sgDimensionArrowTypeNames[ArrowType]);
      if AIns.Block = nil then
      begin
        AIns.Block :=
          TsgDXFBlock(AConverter.NewNamedEntity(AConverter.Sections[csBlocks],
          TsgDXFBlock, sgDimensionArrowTypeNames[ArrowType]));
        GenerateArrow(AConverter, AIns.Block, ArrowType);
        AIns.Block.Loaded(AConverter);
      end;
    end;

  begin
    vRotPt := DistanceFPoint(vLines[2].Point, LinDefPoint1) <
      DistanceFPoint(vLines[3].Point, LinDefPoint1);
    vI1 := Integer(not(vRotPt));
    vI2 := Integer(vRotPt);
    vPoint[vI1] := vLines[2].Point;
    vPoint[vI2] := vLines[3].Point;
    vVisible[vI1] := not DIMSD1;
    vVisible[vI2] := not DIMSD2;
    vDX := vPoint[0].X - vPoint[1].X;
    vDY := vPoint[0].Y - vPoint[1].Y;
    if Abs(vDX) < fAccuracy then
    begin
      vLen := DistanceFPoint(vPoint[0], vPoint[1]);
      if vLen > fAccuracy then
        vAngle := sgFunction.sgArcSin(vDY / vLen)
      else
        vAngle := 0;
    end
    else
      vAngle := ArcTan(vDY / vDX);
    if (vDX < 0) and (not vIsShort) then
      vAngle := vAngle + Pi;
    vAngle := Degree(vAngle);
    vInsert := TsgDXFInsert.Create;
    AConverter.DoCreate(vInsert);
    SetBlock(vInsert, DimArrowType1);
    vInsert.ColorCAD := DIMCLRD;
    vInsert.LineWeight := DIMLWD;
    vInsert.Point := vPoint[0];
    vInsert.Visibility := vVisible[0];
    vInsert.Angle := vAngle;
    vInsert.Scale := MakeFPoint(vArrowSize, vArrowSize, vArrowSize);
    AConverter.Loads(vInsert);
    Block.AddEntity(vInsert);
    vInsert := TsgDXFInsert.Create;
    AConverter.DoCreate(vInsert);
    SetBlock(vInsert, DimArrowType2);
    vInsert.ColorCAD := DIMCLRD;
    vInsert.LineWeight := DIMLWD;
    vInsert.Point := vPoint[1];
    vInsert.Visibility := vVisible[1];
    vInsert.Angle := vAngle + 180;
    vInsert.Scale := MakeFPoint(vArrowSize, vArrowSize, vArrowSize);
    AConverter.Loads(vInsert);
    Block.AddEntity(vInsert);
    if FFlags < 128 then
    begin
      vAngle := vAngle + 180;
      vInsert := TsgDXFInsert.Create;
      AConverter.DoCreate(vInsert);
      vInsert.Block := AConverter.BlockByName(cnstBlockNameLine);
      vInsert.ColorCAD := DIMCLRD;
      vInsert.LineWeight := DIMLWD;
      vInsert.Point := vPoint[0];
      vInsert.Visibility := vVisible[0];
      vInsert.Angle := vAngle;
      vInsert.Scale := MakeFPoint(vExtLineExt, vExtLineExt, vExtLineExt);
      AConverter.Loads(vInsert);
      Block.AddEntity(vInsert);
      vInsert := TsgDXFInsert.Create;
      AConverter.DoCreate(vInsert);
      vInsert.Block := AConverter.BlockByName(cnstBlockNameLine);
      vInsert.ColorCAD := DIMCLRD;
      vInsert.LineWeight := DIMLWD;
      vInsert.Point := vPoint[1];
      vInsert.Visibility := vVisible[1];
      vInsert.Angle := vAngle;
      vInsert.Scale := MakeFPoint(vExtLineExt, vExtLineExt, vExtLineExt);
      AConverter.Loads(vInsert);
      Block.AddEntity(vInsert);
    end;
  end;

  procedure AddText;
  begin
    vTextPoint := cnstFPointZero;
    vTextRot := 0;
    vDimText := TsgDXFText.Create;
    AConverter.DoCreate(vDimText);
    // vText.SetStyle(AConverter.StyleByName(sTextStyleStandardName));
    SetTextString(DistanceFPoint(FLinDefPoint1, FLinDefPoint2));
    vDimText.ColorCAD := DIMCLRT;
    vDimText.Height := GetTextHeightReal;
    vDimText.ApplyStyle(TextStyle);
    TextLoaded;
  end;

  procedure Clear;
  begin
    FDefPoint := cnstFPointZero;
    FLinDefPoint1 := FDefPoint;
    FLinDefPoint2 := FDefPoint;
    FMiddlePoint := FDefPoint;
    FFlags := 255;
  end;

  procedure MakeBlockClosedFilledLine;
  var
    vBlockClosedFilled: TsgDXFBlock;
    vLine: TsgDXFLine;
  begin
    if AConverter.BlockByName(cnstBlockNameLine) = nil then
    begin
      vBlockClosedFilled := TsgDXFBlock.Create;
      vBlockClosedFilled.Name := cnstBlockNameLine;
      vLine := TsgDXFLine.Create;
      vLine.ColorCAD := cnstColorCADByBlock;
      vLine.Point := MakeFPoint(0, -2 / 6, 0);
      vLine.Point1 := MakeFPoint(0, -1, 0);
      vBlockClosedFilled.AddEntity(vLine);
      AConverter.DoCreate(vBlockClosedFilled.Entities[0]);
      AConverter.Loads(vBlockClosedFilled.Entities[0]);
      AConverter.Sections[csBlocks].AddEntity(vBlockClosedFilled);
      AConverter.Loads(vBlockClosedFilled);
    end;
  end;

  function Error: Boolean;
  begin
    Result := (FMiddlePoint.X = FDefPoint.X) and (FMiddlePoint.Y = FDefPoint.Y);
  end;

begin
  vName := Name;
  if vName = '' then
    vName := GetInternalBlockName(AConverter);
  if (vName <> '') and not Error and
    ((FFlags in [0, 1, 128, 129]) and IsInternalDimension) then
  begin
    if Block <> nil then
      Block.Clear(True)
    else
    begin
      Block := TsgDXFBlock.Create;
      Block.Name := vName;
      AConverter.Sections[csBlocks].AddEntity(Block);
    end;
    Block.SetFlags(1);

    vTextOffset := Abs(TextOffset);
    vArrowSize := ArrowSize;
    vExtLineOffset := ExtLineOffset;
    vExtLineExt := ExtLineExt;

    MakeBlockClosedFilledLine;
    Block.FOffset := cnstFPointZero;
    Block.ColorCAD := cnstColorCADByLayer;
    AddPoint;
    AddText;
    AddLines;
    AddSolid;
    // Clear;
    AConverter.Loads(Block);
    Point := cnstFPointZero;
    // Basic parameters of the DIMENSION are set in world coordinates
  end;
end;

procedure TsgDXFDimension.ClearReferences;
begin
  inherited ClearReferences;
  FPropertiesItem.Item := nil;
  Style := nil;
end;

procedure TsgDXFDimension.CopyProperties(const ADim: TsgDXFDimension);
begin
  FPropertiesItem.Item := nil;
  if Assigned(ADim.FPropertiesItem.Item) then
  begin
    FPropertiesItem.Item := TsgDXFDimensionProperties.Create;
    GetProperties.AssignEntity(ADim.FPropertiesItem.Item);
    TsgDXFDimensionProperties(GetProperties).FOwnerStyleItem.Item :=
      FDimStyleItem.Item;
  end;
end;

constructor TsgDXFDimension.Create;
begin
  inherited Create;
  FDimStyleItem := TsgTableItem.Create;
  FPropertiesItem := TsgTableItem.Create;
end;

procedure TsgDXFDimension.CreateBlock(const AConverter: TsgDXFConverter);
begin
  Block := TsgDXFBlock.Create;
  Block.Name := GetInternalBlockName(AConverter);
  AConverter.FBlocksSection.AddEntity(Block);
end;

function TsgDXFDimension.GetArcDefPoint: TFPoint;
begin
  Result := FArcDefPoint;
end;

function TsgDXFDimension.GetArrowSize: TsgFloat;
begin
  Result := ActualDimStyle.ArrowSize;
end;

function TsgDXFDimension.GetArrowType: Byte;
begin
  Result := sgConsts.GetArrowByte(DIMBLKT);
end;

function TsgDXFDimension.GetArrowType1: Byte;
begin
  Result := sgConsts.GetArrowByte(DimArrowType1);
end;

function TsgDXFDimension.GetArrowType2: Byte;
begin
  Result := sgConsts.GetArrowByte(DimArrowType2);
end;

function TsgDXFDimension.GetArrowTypeL: Byte;
begin
  Result := sgConsts.GetArrowByte(DIMLDRBLKT);
end;

function TsgDXFDimension.GetDefPoint: TFPoint;
begin
  Result := FDefPoint;
end;

function TsgDXFDimension.GetDimStyleInternal: Pointer;
begin
  Result := Style;
end;

function TsgDXFDimension.GetTextStyleInternal: Pointer;
begin
  Result := TextStyle; // Style.TextStyle
end;

function TsgDXFDimension.GetDimArrowType1: TsgDimArrowType;
begin
  Result := ActualDimStyle.DimArrowType1;
  // GetDimArrowTypeByDimSah(DIMSAH, PropertyInit[vnDIMBLK],
  // PropertyInit[vnDIMBLK1], DIMBLKT, DIMBLK1T, FDimStyleItem.DimArrowType1);
end;

function TsgDXFDimension.GetDimArrowType2: TsgDimArrowType;
begin
  Result := ActualDimStyle.DimArrowType2;
  // Result := GetDimArrowTypeByDimSah(DIMSAH, ActualDimStyle.PropertyInit[vnDIMBLK],
  // ActualDimStyle.PropertyInit[vnDIMBLK2], DIMBLKT, DIMBLK2T, FDimStyleItem.DimArrowType2);
end;

function TsgDXFDimension.GetDIMBLK: TsgDXFBlock;
begin
  Result := ActualDimStyle.DIMBLK;
end;

function TsgDXFDimension.GetDimBlk1: TsgDXFBlock;
begin
  Result := ActualDimStyle.DimBlk1;
end;

function TsgDXFDimension.GetDIMBLK1T: TsgDimArrowType;
begin
  Result := ActualDimStyle.DIMBLK1T;
end;

function TsgDXFDimension.GetDimBlk2: TsgDXFBlock;
begin
  Result := ActualDimStyle.DimBlk2;
end;

function TsgDXFDimension.GetDIMBLK2T: TsgDimArrowType;
begin
  Result := ActualDimStyle.DIMBLK2T;
end;

function TsgDXFDimension.GetDIMBLKT: TsgDimArrowType;
begin
  Result := ActualDimStyle.DIMBLKT;
end;

function TsgDXFDimension.GetDIMCLRD: TsgColorCAD;
begin
  Result := ActualDimStyle.DIMCLRD;
end;

function TsgDXFDimension.GetDIMCLRE: TsgColorCAD;
begin
  Result := ActualDimStyle.DIMCLRE;
end;

function TsgDXFDimension.GetDIMCLRT: TsgColorCAD;
begin
  Result := ActualDimStyle.DIMCLRT;
end;

function TsgDXFDimension.GetDimType: TsgDimensionType;
begin
  Result := GetDimensionType(FFlags);
end;

function TsgDXFDimension.GetDIMLDRBLK: TsgDXFBlock;
begin
  Result := ActualDimStyle.DIMLDRBLK;
end;

function TsgDXFDimension.GetDIMLDRBLKT: TsgDimArrowType;
begin
  Result := ActualDimStyle.DIMLDRBLKT;
end;

function TsgDXFDimension.GetDIMLWD: TsgFloat;
begin
  Result := ActualDimStyle.DIMLWD;
end;

function TsgDXFDimension.GetDIMLWE: TsgFloat;
begin
  Result := ActualDimStyle.DIMLWE;
end;

function TsgDXFDimension.GetDIMSAH: Boolean;
begin
  Result := ActualDimStyle.DIMSAH;
end;

function TsgDXFDimension.GetDIMSD1: Boolean;
begin
  Result := ActualDimStyle.DIMSD1;
end;

function TsgDXFDimension.GetDIMSD2: Boolean;
begin
  Result := ActualDimStyle.DIMSD2;
end;

function TsgDXFDimension.GetDIMSE1: Boolean;
begin
  Result := ActualDimStyle.DIMSE1;
end;

function TsgDXFDimension.GetDIMSE2: Boolean;
begin
  Result := ActualDimStyle.DIMSE2;
end;

function TsgDXFDimension.GetDIMTIH: Boolean;
begin
  Result := ActualDimStyle.DIMTIH;
end;

function TsgDXFDimension.GetDIMTOH: Boolean;
begin
  Result := ActualDimStyle.DIMTOH;
end;

function TsgDXFDimension.GetStyle: TsgDXFDimensionStyle;
begin
  Result := TsgDXFDimensionStyle(FDimStyleItem.Item);
end;

function TsgDXFDimension.GetEntType: TsgCADEntities;
begin
  Result := ceDimension;
end;

function TsgDXFDimension.GetExtData(const AData: TsgCADExtendedData): Boolean;
begin
  Result := False;
  if FPropertiesItem.Item is TsgDXFDimensionProperties then
  begin
    BeginExtData(AData);
    Result := FPropertiesItem.Item.GetExtData(AData);
    EndExtData(AData);
  end;
end;

function TsgDXFDimension.GetExtLineExt: TsgFloat;
begin
  Result := ActualDimStyle.ExtLineExt;
end;

function TsgDXFDimension.GetExtLineOffset: TsgFloat;
begin
  Result := ActualDimStyle.ExtLineOffset;
end;

function TsgDXFDimension.GetFlags: Integer;
begin
  Result := FFlags;
end;

function TsgDXFDimension.GetForceText: Integer;
begin
  Result := ActualDimStyle.DIMTIX;
end;

function TsgDXFDimension.GetInternalBlockName(const AConverter
  : TsgDXFConverter): string;
var
  vDimBlock: TsgDXFBlock;
begin
  repeat
    Result := cnstInternalBlockPrefix + sInternalDimension +
      IntToStr(AConverter.FAddedDimensionsCount);
    Inc(AConverter.FAddedDimensionsCount);
    vDimBlock := AConverter.BlockByName(Result);
  until vDimBlock = nil;
end;

function TsgDXFDimension.GetLinDefPoint1: TFPoint;
begin
  Result := FLinDefPoint1;
end;

function TsgDXFDimension.GetLinDefPoint2: TFPoint;
begin
  Result := FLinDefPoint2;
end;

function TsgDXFDimension.GetMeasurementsScale: Double;
begin
  Result := ActualDimStyle.DimLFac;
end;

function TsgDXFDimension.GetTextAlign: Integer;
begin
  Result := ActualDimStyle.TextAlign;
end;

function TsgDXFDimension.GetTextHeight: TsgFloat;
begin
  Result := ActualDimStyle.TextHeight;
end;

function TsgDXFDimension.GetTextHeightReal: TsgFloat;
begin
  ActualDimStyle.GetTextHeightReal(Result);
end;

function TsgDXFDimension.GetTextOffset: TsgFloat;
begin
  Result := ActualDimStyle.TextOffset;
end;

function TsgDXFDimension.GetTextOverride: string;
begin
  Result := FTextOverride;
end;

function TsgDXFDimension.GetTextPosVert: TsgDimTextPosVert;
begin
  Result := ActualDimStyle.TextPosVert;
end;

function TsgDXFDimension.GetTextRotation: Double;
begin
  Result := FTextRotation;
end;

function TsgDXFDimension.GetTextStyle: TsgDXFStyle;
begin
  Result := ActualDimStyle.TextStyle;
end;

function TsgDXFDimension.GetBlockOffset: TFPoint;
begin
  Result := cnstFPointZero;
end;

procedure TsgDXFDimension.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(FPropertiesItem.Item) then
    FPropertiesItem.Item.Link(AConverter);
  if Assigned(Style) and (Style.ClassType = TsgLinkObject) then
    Style := TsgDXFDimensionStyle(TsgLinkObject(Style)
      .GetObject(AConverter.Sections[csDimStyles]));
  if Assigned(TextStyle) and (TextStyle.ClassType = TsgLinkObject) then
    TextStyle := TsgDXFStyle(TsgLinkObject(TextStyle)
      .GetObject(AConverter.Sections[csStyles]));
  if Assigned(DIMBLK) and (DIMBLK.ClassType = TsgLinkObject) then
    DIMBLK := TsgDXFBlock(TsgLinkObject(DIMBLK)
      .GetObject(AConverter.Sections[csBlockRecords]));
  if Assigned(DIMLDRBLK) and (DIMLDRBLK.ClassType = TsgLinkObject) then
    DIMLDRBLK := TsgDXFBlock(TsgLinkObject(DIMLDRBLK)
      .GetObject(AConverter.Sections[csBlockRecords]));
  if Assigned(DimBlk1) and (DimBlk1.ClassType = TsgLinkObject) then
    DimBlk1 := TsgDXFBlock(TsgLinkObject(DimBlk1)
      .GetObject(AConverter.Sections[csBlockRecords]));
  if Assigned(DimBlk2) and (DimBlk2.ClassType = TsgLinkObject) then
    DimBlk2 := TsgDXFBlock(TsgLinkObject(DimBlk2)
      .GetObject(AConverter.Sections[csBlockRecords]));
end;

procedure TsgDXFDimension.LoadedInternal(AConverter: TsgDXFConverter);
(* // For future versions
  var
  I: Integer;
  vMText: TsgDXFMText; *)
begin
  if Style = nil then
    Style := AConverter.DimensionStyleByName(sStandardName);

  if not(AConverter.FStatus = stLoading) and IsInternalDimension then
    GenerateBlock(AConverter); // Creation of the empty dimension block

  (* // For future versions
    else
    if (FBlock <> nil) and (FTextOverride <> '') then
    begin
    vMText := nil;
    for I := 0 to FBlock.Count-1 do
    if FBlock.Entities[I].EntType=ceMText then
    begin
    vMText := TsgDXFMText(FBlock.Entities[I]);
    Break;
    end;
    if vMText = nil then
    begin
    vMText := TsgDXFMText.Create;
    if Assigned(AConverter.OnCreate) then
    AConverter.OnCreate(vMText);
    FBlock.FLoaded := False;
    Block.AddEntity(vMText);
    end;
    if (FTextOverride <> vMText.Text) and (AnsiPos('<>', FTextOverride)=0) then
    begin
    vMText.Point := FMiddlePoint;
    vMText.Height := TextHeight;
    vMText.Text := FTextOverride;
    vMText.Loaded(AConverter);
    FBlock.Loaded(AConverter);
    end;
    end; *)
  inherited LoadedInternal(AConverter);
end;

procedure TsgDXFDimension.ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord);

  function _IsInternalDimensionBlockRecord(ABlockRecord
    : TsgDXFBlockRecord): Boolean;
  begin
    if ABlockRecord <> nil then
      Result := AnsiPos(sInternalDimension, TryLinkToName(ABlockRecord)) <> 0
    else
      Result := True;
  end;

begin
  if not _IsInternalDimensionBlockRecord(ABlockRecord) then
    inherited ReferenceBlockRecord(ABlockRecord);
end;

procedure TsgDXFDimension.SetArcDefPoint(const Value: TFPoint);
begin
  FArcDefPoint := Value;
end;

procedure TsgDXFDimension.SetArrowSize(const Value: TsgFloat);
begin
  if Value >= 0 then
    ActualDimStyle.ArrowSize := Value;
end;

procedure TsgDXFDimension.SetArrowType(const Value: Byte);
begin
  DIMBLKT := sgConsts.GetArrowType(Value);
end;

procedure TsgDXFDimension.SetArrowType1(const Value: Byte);
begin
  DimArrowType1 := sgConsts.GetArrowType(Value);
end;

procedure TsgDXFDimension.SetArrowType2(const Value: Byte);
begin
  DimArrowType2 := sgConsts.GetArrowType(Value);
end;

procedure TsgDXFDimension.SetArrowTypeL(const Value: Byte);
begin
  DIMLDRBLKT := sgConsts.GetArrowType(Value);
end;

procedure TsgDXFDimension.SetConverter(const AConverter: TsgDXFConverter);
begin
  inherited SetConverter(AConverter);
  if Assigned(FPropertiesItem.Item) then
    FPropertiesItem.Item.SetConverter(AConverter);
end;

procedure TsgDXFDimension.SetDefPoint(const Value: TFPoint);
begin
  FDefPoint := Value;
end;

procedure TsgDXFDimension.SetDimArrowType1(const Value: TsgDimArrowType);
begin
  if not DIMSAH then
    DIMBLK2T := DIMBLKT;
  DIMSAH := True;
  DIMBLK1T := Value;
  if DIMBLK1T = datClosedfilled then
    DIMBLKT := datClosedfilled;
end;

procedure TsgDXFDimension.SetDimArrowType2(const Value: TsgDimArrowType);
begin
  if not DIMSAH then
    DIMBLK1T := DIMBLKT;
  DIMSAH := True;
  DIMBLK2T := Value;
  if DIMBLK2T = datClosedfilled then
    DIMBLKT := datClosedfilled;
end;

procedure TsgDXFDimension.SetDIMBLK(const Value: TsgDXFBlock);
begin
  ActualDimStyle.DIMBLK := Value;
end;

procedure TsgDXFDimension.SetDimBlk1(const Value: TsgDXFBlock);
begin
  ActualDimStyle.DimBlk1 := Value;
end;

procedure TsgDXFDimension.SetDIMBLK1T(const Value: TsgDimArrowType);
begin
  ActualDimStyle.DIMBLK1T := Value;
end;

procedure TsgDXFDimension.SetDimBlk2(const Value: TsgDXFBlock);
begin
  ActualDimStyle.DimBlk2 := Value;
end;

procedure TsgDXFDimension.SetDIMBLK2T(const Value: TsgDimArrowType);
begin
  ActualDimStyle.DIMBLK2T := Value;
end;

procedure TsgDXFDimension.SetDIMBLKT(const Value: TsgDimArrowType);
begin
  ActualDimStyle.DIMBLKT := Value;
end;

procedure TsgDXFDimension.SetDIMCLRD(const Value: TsgColorCAD);
begin
  ActualDimStyle.DIMCLRD := Value;
end;

procedure TsgDXFDimension.SetDIMCLRE(const Value: TsgColorCAD);
begin
  ActualDimStyle.DIMCLRE := Value;
end;

procedure TsgDXFDimension.SetDIMCLRT(const Value: TsgColorCAD);
begin
  ActualDimStyle.DIMCLRT := Value;
end;

procedure TsgDXFDimension.SetDIMLDRBLK(const Value: TsgDXFBlock);
begin
  ActualDimStyle.DIMLDRBLK := Value;
end;

procedure TsgDXFDimension.SetDIMLDRBLKT(const Value: TsgDimArrowType);
begin
  ActualDimStyle.DIMLDRBLKT := Value;
end;

procedure TsgDXFDimension.SetDIMLWD(const Value: TsgFloat);
begin
  ActualDimStyle.DIMLWD := Value;
end;

procedure TsgDXFDimension.SetDIMLWE(const Value: TsgFloat);
begin
  ActualDimStyle.DIMLWE := Value;
end;

procedure TsgDXFDimension.SetDIMSAH(const Value: Boolean);
begin
  ActualDimStyle.DIMSAH := Value;
end;

procedure TsgDXFDimension.SetDIMSD1(const Value: Boolean);
begin
  ActualDimStyle.DIMSD1 := Value;
end;

procedure TsgDXFDimension.SetDIMSD2(const Value: Boolean);
begin
  ActualDimStyle.DIMSD2 := Value;
end;

procedure TsgDXFDimension.SetDIMSE1(const Value: Boolean);
begin
  ActualDimStyle.DIMSE1 := Value;
end;

procedure TsgDXFDimension.SetDIMSE2(const Value: Boolean);
begin
  ActualDimStyle.DIMSE2 := Value;
end;

procedure TsgDXFDimension.SetDIMTIH(const Value: Boolean);
begin
  ActualDimStyle.DIMTIH := Value;
end;

procedure TsgDXFDimension.SetDIMTOH(const Value: Boolean);
begin
  ActualDimStyle.DIMTOH := Value;
end;

procedure TsgDXFDimension.SetExtLineExt(const Value: TsgFloat);
begin
  ActualDimStyle.ExtLineExt := Value;
end;

procedure TsgDXFDimension.SetExtLineOffset(const Value: TsgFloat);
begin
  ActualDimStyle.ExtLineOffset := Value;
end;

procedure TsgDXFDimension.SetFlags(const Value: Integer);
begin
  FFlags := Value;
end;

procedure TsgDXFDimension.SetForceText(const Value: Integer);
begin
  ActualDimStyle.DIMTIX := Value;
end;

procedure TsgDXFDimension.SetLinDefPoint1(const Value: TFPoint);
begin
  FLinDefPoint1 := Value;
end;

procedure TsgDXFDimension.SetLinDefPoint2(const Value: TFPoint);
begin
  FLinDefPoint2 := Value;
end;

procedure TsgDXFDimension.SetMeasurementsScale(const Value: Double);
begin
  ActualDimStyle.DimLFac := Value;
end;

procedure TsgDXFDimension.SetPrecision(const Value: Integer);
begin
  ActualDimStyle.DIMDEC := Value;
end;

procedure TsgDXFDimension.SetRadDefPoint(const Value: TFPoint);
begin
  FRadDefPoint := Value;
end;

procedure TsgDXFDimension.SetStyle(ADimStyle: TsgDXFDimensionStyle);
begin
  SetStyleInternal(ADimStyle);
  if GetProperties <> nil then
    GetProperties.SetOwnerStyle(TsgDXFDimensionStyle(FDimStyleItem.Item));
end;

procedure TsgDXFDimension.SetStyleInternal(const AValue: TsgDXFDimensionStyle);
begin
  FDimStyleItem.Item := AValue;
end;

procedure TsgDXFDimension.SetTextAlign(const Value: Integer);
begin
  ActualDimStyle.TextAlign := Value;
end;

procedure TsgDXFDimension.SetTextHeight(const Value: TsgFloat);
begin
  ActualDimStyle.TextHeight := Value;
end;

procedure TsgDXFDimension.SetTextOffset(const Value: TsgFloat);
begin
  ActualDimStyle.TextOffset := Value;
end;

procedure TsgDXFDimension.SetTextOverride(const Value: string);
begin
  FTextOverride := Value;
end;

procedure TsgDXFDimension.SetTextPosVert(const Value: TsgDimTextPosVert);
begin
  ActualDimStyle.TextPosVert := Value;
end;

procedure TsgDXFDimension.SetTextRotation(const Value: Double);
begin
  FTextRotation := Value;
end;

procedure TsgDXFDimension.SetTextStyle(const Value: TsgDXFStyle);
begin
  ActualDimStyle.TextStyle := Value;
end;

function TsgDXFDimension.ToXMLGeoData(const ANode: TsgNode;
  const AMode: TsgXMLModes): Integer;
begin
  Result := inherited ToXMLGeoData(ANode, AMode);
end;

function TsgDXFDimension.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes): Integer;

begin
  Result := inherited ToXMLNode(ANode, AMode);
  if IsXMLHelp(AMode) then
  begin
    ANode.AddAttribNV(cnstXMLNames[xmlDimStyle].Name);
    ANode.AddChildNV(cnstXMLNames[xmlProperties].Name);
    ANode.AddAttribNV(cnstXMLNames[xmlDefPoint].Name);
    ANode.AddAttribNV(cnstXMLNames[xmlLinDefPoint1].Name);
    ANode.AddAttribNV(cnstXMLNames[xmlLinDefPoint2].Name);
    ANode.AddAttribNV(cnstXMLNames[xmlMiddlePoint].Name);
    ANode.AddAttribNV(cnstXMLNames[xmlArcDefPoint].Name);
    ANode.AddAttribNV(cnstXMLNames[xmlRadDefPoint].Name);
  end
  else
  begin
    if Assigned(Style) then
      ANode.AddAttribNV(cnstXMLNames[xmlDimStyle].Name).ValueAsStr :=
        Style.Name;
    if Assigned(Properties) then
      Properties.ToXMLAsProperties
        (ANode.AddChildNV(cnstXMLNames[xmlProperties].Name), AMode);
    // change in future version - export by dimtype
    ANode.AddAttribNV(cnstXMLNames[xmlDefPoint].Name).ValueAsFPoint := DefPoint;
    ANode.AddAttribNV(cnstXMLNames[xmlLinDefPoint1].Name).ValueAsFPoint :=
      LinDefPoint1;
    ANode.AddAttribNV(cnstXMLNames[xmlLinDefPoint2].Name).ValueAsFPoint :=
      LinDefPoint2;
    ANode.AddAttribNV(cnstXMLNames[xmlMiddlePoint].Name).ValueAsFPoint :=
      MiddlePoint;
    if not(DimType in [dmtRotHorVert, dmtAligned, dmtOrdinate]) then
    begin
      ANode.AddAttribNV(cnstXMLNames[xmlArcDefPoint].Name).ValueAsFPoint :=
        ArcDefPoint;
      ANode.AddAttribNV(cnstXMLNames[xmlRadDefPoint].Name).ValueAsFPoint :=
        RadDefPoint;
    end;
  end;
  ANode.AddAttribNV(cnstXMLNames[xmlArrowType].Name).ValueAsInt := ArrowType;
  ANode.AddAttribNV(cnstXMLNames[xmlArrowSize].Name).ValueAsDouble := ArrowSize;
end;

function TsgDXFDimension.UseTextStyleFixedHeight: Boolean;
var
  vHeight: Double;
begin
  Result := not ActualDimStyle.GetTextHeightReal(vHeight);
end;

function TsgDXFDimension.IsInternalDimension: Boolean;
begin
  Result := Block = nil;
  if not Result then
    Result := AnsiPos(sInternalDimension, TryLinkToName(Block)) <> 0;
end;

{ TsgDXFDimensionStyle }

procedure TsgDXFDimensionStyle.ClearReferences;
var
  I: TsgDimNameVal;
begin
  inherited ClearReferences;
  FTextStyleItem.Item := nil;
  for I := Low(FBlks) to High(FBlks) do
    SetBlocksInternal(I, nil);
end;

constructor TsgDXFDimensionStyle.Create;
begin
  inherited Create;
  FTextStyleItem := TsgTableItem.Create;
  Name := sStandardName;
  InitProps(nil);
end;

function TsgDXFDimensionStyle.GetASZ: TsgFloat;
begin
  Result := GetActualStyle(vnDIMASZ).FDimProps.Asz;
end;

function TsgDXFDimensionStyle.GetArrowTypeByBlock(const ABlock: TsgDXFBlock)
  : TsgDimArrowType;
var
  LinkObject: TsgLinkObject absolute ABlock;
begin
  Result := datClosedfilled;
  if Assigned(ABlock) then
  begin
    if ABlock.ClassType = TsgLinkObject then
    begin
      case LinkObject.LinkType of
        lodtName:
          Result := GetArrowTypeByName(LinkObject.Name, datUserarrow);
        lodtDimArrow:
          Result := LinkObject.FData.ArrowType;
      else
        Result := datUserarrow;
      end;
    end
    else
      Result := GetArrowTypeByName(ABlock.Name, datUserarrow);
  end
end;

function TsgDXFDimensionStyle.GetArrowType: Byte;
begin
  Result := sgConsts.GetArrowByte(GetDIMBLKT);
end;

function TsgDXFDimensionStyle.GetArrowType1: Byte;
begin
  Result := sgConsts.GetArrowByte(GetDIMBLK1T);
end;

function TsgDXFDimensionStyle.GetArrowType2: Byte;
begin
  Result := sgConsts.GetArrowByte(GetDIMBLK2T);
end;

function TsgDXFDimensionStyle.GetArrowTypeL: Byte;
begin
  Result := sgConsts.GetArrowByte(GetDIMLDRBLKT);
end;

function TsgDXFDimensionStyle.GetBlocks(const AType: TsgDimNameVal)
  : TsgDXFBlock;
begin
  Result := GetActualStyle(AType).FBlks[AType];
end;

function TsgDXFDimensionStyle.GetCLRD: TsgColorCAD;
begin
  Result := GetActualStyle(vnDIMCLRD).FDimProps.ClrD;
end;

function TsgDXFDimensionStyle.GetCLRE: TsgColorCAD;
begin
  Result := GetActualStyle(vnDIMCLRE).FDimProps.ClrE;
end;

function TsgDXFDimensionStyle.GetCLRT: TsgColorCAD;
begin
  Result := GetActualStyle(vnDIMCLRT).FDimProps.ClrT;
end;

function TsgDXFDimensionStyle.GetDEC: Integer;
begin
  Result := GetActualStyle(vnDIMDEC).FDimProps.Dec;
end;

function TsgDXFDimensionStyle.GetDimArrowType1: TsgDimArrowType;
begin
  Result := GetDimArrowTypeByDimSah(DIMSAH, DIMBLKT, DIMBLK1T);
end;

function TsgDXFDimensionStyle.GetDimArrowType2: TsgDimArrowType;
begin
  Result := GetDimArrowTypeByDimSah(DIMSAH, DIMBLKT, DIMBLK2T);
end;

function TsgDXFDimensionStyle.GetDIMBLKT: TsgDimArrowType;
begin
  Result := FDimProps.Arrows.Blks[vnDIMBLK];
  if Result = datUndefined then
    Result := datClosedfilled;
end;

function TsgDXFDimensionStyle.GetDIMBLK1T: TsgDimArrowType;
begin
  Result := FDimProps.Arrows.Blks[vnDIMBLK1];
  if Result = datUndefined then
    Result := GetDIMBLKT;
end;

function TsgDXFDimensionStyle.GetDIMBLK2T: TsgDimArrowType;
begin
  Result := FDimProps.Arrows.Blks[vnDIMBLK2];
  if Result = datUndefined then
    Result := GetDIMBLKT;
end;

function TsgDXFDimensionStyle.GetDIMLDRBLKT: TsgDimArrowType;
begin
  Result := FDimProps.Arrows.Blks[vnDIMLRBLK];
  if Result = datUndefined then
    Result := GetDIMBLKT;
end;

function TsgDXFDimensionStyle.GetDIMBLK: TsgDXFBlock;
begin
  Result := FBlks[vnDIMBLK];
end;

function TsgDXFDimensionStyle.GetDimBlk1: TsgDXFBlock;
begin
  Result := GetActualStyle(vnDIMBLK1).FBlks[vnDIMBLK1];
  if not Assigned(Result) then
    Result := DIMBLK;
end;

function TsgDXFDimensionStyle.GetDimBlk2: TsgDXFBlock;
begin
  Result := GetActualStyle(vnDIMBLK2).FBlks[vnDIMBLK2];
  if not Assigned(Result) then
    Result := DIMBLK;
end;

function TsgDXFDimensionStyle.GetDIMLDRBLK: TsgDXFBlock;
begin
  Result := GetActualStyle(vnDIMLRBLK).FBlks[vnDIMLRBLK];
  if not Assigned(Result) then
    Result := DIMBLK;
end;

function TsgDXFDimensionStyle.GetDIMSAH: Boolean;
begin
  Result := GetActualStyle(vnDIMSAH).FDimProps.Sah;
end;

function TsgDXFDimensionStyle.GetDIMSD1: Boolean;
begin
  Result := GetActualStyle(vnDIMSD1).FDimProps.SD1;
end;

function TsgDXFDimensionStyle.GetDIMSD2: Boolean;
begin
  Result := GetActualStyle(vnDIMSD2).FDimProps.SD2;
end;

function TsgDXFDimensionStyle.GetDIMSE1: Boolean;
begin
  Result := GetActualStyle(vnDIMSE1).FDimProps.SE1;
end;

function TsgDXFDimensionStyle.GetDIMSE2: Boolean;
begin
  Result := GetActualStyle(vnDIMSE2).FDimProps.SE2;
end;

function TsgDXFDimensionStyle.GetDIMTIH: Boolean;
begin
  Result := GetActualStyle(vnDIMTIH).FDimProps.Tih;
end;

function TsgDXFDimensionStyle.GetDIMTOH: Boolean;
begin
  Result := GetActualStyle(vnDIMTOH).FDimProps.Toh;
end;

function TsgDXFDimensionStyle.GetEXE: TsgFloat;
begin
  Result := GetActualStyle(vnDIMEXE).FDimProps.Exe;
end;

function TsgDXFDimensionStyle.GetEXO: TsgFloat;
begin
  Result := GetActualStyle(vnDIMEXO).FDimProps.Exo
end;

function TsgDXFDimensionStyle.GetLFAC: Double;
begin
  Result := GetActualStyle(vnDIMLFAC).FDimProps.LFac;
end;

function TsgDXFDimensionStyle.GetLWD: TsgFloat;
begin
  Result := GetActualStyle(vnDIMLWD).FDimProps.LwD;
end;

function TsgDXFDimensionStyle.GetLWE: TsgFloat;
begin
  Result := GetActualStyle(vnDIMLWE).FDimProps.LwE;
end;

function TsgDXFDimensionStyle.GetOwnerStyle: TsgDXFDimensionStyle;
begin
  Result := nil;
end;

function TsgDXFDimensionStyle.GetPropertiesInit: TsgDimNameVals;
begin
  Result := [];
end;

function TsgDXFDimensionStyle.GetActualStyle(const ANameValue: TsgDimNameVal;
  const ASetValue: Boolean = False): TsgDXFDimensionStyle;
begin
  Result := Self;
end;

function TsgDXFDimensionStyle.GetScale: Double;
begin
  Result := GetActualStyle(vnDIMSCALE).FDimProps.Scale;
end;

function TsgDXFDimensionStyle.GetCEN: TsgFloat;
begin
  Result := GetActualStyle(vnDIMCEN).FDimProps.Cen;
end;

function TsgDXFDimensionStyle.GetTextAlign: Integer;
begin
  if DIMTIH then
    Result := 0 // gorizontal - default
  else
  begin
    if DIMTOH then
      Result := 2 // ISO
    else
      Result := 1; // align
  end;
end;

// false - lock value
function TsgDXFDimensionStyle.GetTextHeightReal(var AHeight: Double): Boolean;
begin
  if Assigned(TextStyle) then
    AHeight := TextStyle.FixedHeight
  else
    AHeight := 0;
  Result := AHeight = 0;
  if Result then
    AHeight := TextHeight;
end;

function TsgDXFDimensionStyle.GetTXT: TsgFloat;
begin
  Result := GetActualStyle(vnDIMTXT).FDimProps.Txt;
end;

function TsgDXFDimensionStyle.GetGAP: TsgFloat;
begin
  Result := GetActualStyle(vnDIMGAP).FDimProps.GAP;
end;

function TsgDXFDimensionStyle.GetTAD: TsgDimTextPosVert;
begin
  Result := TsgDimTextPosVert(GetActualStyle(vnDIMTAD).FDimProps.Tad);
end;

function TsgDXFDimensionStyle.GetTXSTY: TsgDXFStyle;
begin
  Result := TsgDXFStyle(GetActualStyle(vnDIMTXSTY).FTextStyleItem.Item);
end;

function TsgDXFDimensionStyle.GetTIX: Integer;
begin
  Result := GetActualStyle(vnDIMTIX).FDimProps.Tix;
end;

procedure TsgDXFDimensionStyle.InitProps(AHeader: PsgHeadVarStruct);
begin
  if AHeader = nil then
    AHeader := @cnstDefHeadVarStruct;
  FDimProps := AHeader^.DimProps;
  FTextStyleItem.Item := nil;
end;

procedure TsgDXFDimensionStyle.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(TextStyle) and (TextStyle.ClassType = TsgLinkObject) then
    TextStyle := TsgDXFStyle(TsgLinkObject(TextStyle)
      .GetObject(AConverter.Sections[csStyles]));
  if Assigned(DIMBLK) and (DIMBLK.ClassType = TsgLinkObject) then
    DIMBLK := TsgDXFBlock(TsgLinkObject(DIMBLK)
      .GetObject(AConverter.Sections[csBlockRecords]));
  if Assigned(DIMLDRBLK) and (DIMLDRBLK.ClassType = TsgLinkObject) then
    DIMLDRBLK := TsgDXFBlock(TsgLinkObject(DIMLDRBLK)
      .GetObject(AConverter.Sections[csBlockRecords]));
  if Assigned(DimBlk1) and (DimBlk1.ClassType = TsgLinkObject) then
    DimBlk1 := TsgDXFBlock(TsgLinkObject(DimBlk1)
      .GetObject(AConverter.Sections[csBlockRecords]));
  if Assigned(DimBlk2) and (DimBlk2.ClassType = TsgLinkObject) then
    DimBlk2 := TsgDXFBlock(TsgLinkObject(DimBlk2)
      .GetObject(AConverter.Sections[csBlockRecords]));
end;

procedure TsgDXFDimensionStyle.LoadedInternal(AConverter: TsgDXFConverter);
var
  I: TsgDimNameVal;
begin
  inherited LoadedInternal(AConverter);
  if Assigned(Converter) then
  begin
    for I := Low(FBlks) to High(FBlks) do
      if FBlks[I] = nil then
        SetArrowTypeEx(FDimProps.Arrows.Blks[I], I);
  end;
end;

procedure TsgDXFDimensionStyle.RemoveReferenceNotification
  (const ARefObj: TsgDXFEntity);
begin
  inherited RemoveReferenceNotification(ARefObj);
  ReplaceBlock(TsgDXFBlock(ARefObj), nil);
end;

function TsgDXFDimensionStyle.ReplaceBlock(const ABlockPrev,
  ABlockNew: TsgDXFBlock): Boolean;
var
  I: TsgDimNameVal;
begin
  Result := False;
  for I := Low(FBlks) to High(FBlks) do
  begin
    if FBlks[I] = ABlockPrev then
    begin
      SetBlocks(I, ABlockNew);
      Result := True;
    end;
  end;
end;

procedure TsgDXFDimensionStyle.SetArrows(AArrows: TsgArrows);
begin
  SetArrowTypeEx(AArrows.Blks[vnDIMBLK], vnDIMBLK);
  SetArrowTypeEx(AArrows.Blks[vnDIMBLK1], vnDIMBLK1);
  SetArrowTypeEx(AArrows.Blks[vnDIMBLK2], vnDIMBLK2);
end;

procedure TsgDXFDimensionStyle.SetASZ(const Value: TsgFloat);
begin
  if Value >= 0 then
    GetActualStyle(vnDIMASZ, True).FDimProps.Asz := Value;
end;

procedure TsgDXFDimensionStyle.SetArrowType(const Value: Byte);
begin
  SetDIMBLKT(sgConsts.GetArrowType(Value));
end;

procedure TsgDXFDimensionStyle.SetArrowType1(const Value: Byte);
begin
  SetDIMBLK1T(sgConsts.GetArrowType(Value));
end;

procedure TsgDXFDimensionStyle.SetArrowType2(const Value: Byte);
begin
  SetDIMBLK2T(sgConsts.GetArrowType(Value));
end;

procedure TsgDXFDimensionStyle.SetArrowTypeL(const Value: Byte);
begin
  SetDIMLDRBLKT(sgConsts.GetArrowType(Value));
end;

procedure TsgDXFDimensionStyle.SetBlocks(const AType: TsgDimNameVal;
  const AValue: string; AConverter: TsgDXFConverter);
begin
  SetConverter(AConverter);
  SetArrowTypeEx(AValue, AType);
end;

procedure TsgDXFDimensionStyle.SetBlocksInternal(const AType: TsgDimNameVal;
  const AValue: TsgDXFBlock);
var
  I: TsgDimNameVal;
begin
  if AValue <> FBlks[AType] then
  begin
    if Assigned(FBlks[AType]) then
    begin
      I := Low(FBlks);
      while (I <= High(FBlks)) and
        ((I = AType) or (FBlks[I] <> FBlks[AType])) do
        Inc(I);
      if (I > High(FBlks)) and FBlks[AType].InheritsFrom(TsgDXFBlock) then
        FBlks[AType].References.Remove(Self);
      // if FBlks[AType].ClassType = TsgLinkObject then
      // TsgLinkObject(FBlks[AType]).Refs.Remove(Self);
    end;
    FBlks[AType] := AValue;
    if Assigned(FBlks[AType]) then
    begin
      if FBlks[AType].ClassType = TsgDXFBlockRecord then
        FBlks[AType] := TsgDXFBlockRecord(FBlks[AType]).Block;
      if FBlks[AType].InheritsFrom(TsgDXFBlock) then
        FBlks[AType].References.Add(Self);
      // if FBlks[AType].ClassType = TsgLinkObject then
      // TsgLinkObject(FBlks[AType]).Refs.Add(Self);
    end;
  end;
  FDimProps.Arrows.Blks[AType] := GetArrowTypeByBlock(FBlks[AType]);
end;

procedure TsgDXFDimensionStyle.SetBlocks(const AType: TsgDimNameVal;
  const AValue: TsgDXFBlock);
var
  vActStyle: TsgDXFDimensionStyle;
begin
  vActStyle := GetActualStyle(AType, True);
  if Assigned(vActStyle) then
    vActStyle.SetBlocksInternal(AType, AValue);
end;

procedure TsgDXFDimensionStyle.SetArrowTypeEx(const AValue: TsgDimArrowType;
  const APropName: TsgDimNameVal);
begin
  case AValue of
    datUndefined, datUserarrow:
      GetActualStyle(APropName, True).FDimProps.Arrows.Blks[APropName]
        := AValue;
  else
    SetArrowTypeEx(sgDimensionArrowTypeNames[AValue], APropName, AValue);
  end;
end;

procedure TsgDXFDimensionStyle.SetArrowTypeEx(const AValue: string;
  const APropName: TsgDimNameVal; AValueType: TsgDimArrowType = datUndefined);
var
  vBlocks: TsgDXFTable;
  vBlock: TsgDXFBlock;
  vName: string;
begin
  vName := AValue;
  if (Length(vName) < 1) and (AValueType <> datUndefined) then
    vName := sgDimensionArrowTypeNames[AValueType];
  if Assigned(Converter) and (Length(vName) > 0) then
  begin
    vBlocks := TsgDXFTable(Converter.Sections[csBlocks]);
    vBlock := TsgDXFBlock(vBlocks.FindEntByName(vName));
    if not Assigned(vBlock) then
    begin
      vBlock := TsgDXFBlock(Converter.NewNamedEntity(vBlocks,
        TsgDXFBlock, vName));
      if AValueType = datUndefined then
        AValueType := GetArrowTypeByName(AValue, datClosedfilled);
      GenerateArrow(Converter, TsgDXFBlock(vBlock), AValueType);
      Converter.Loads(vBlock);
    end;
    SetBlocks(APropName, TsgDXFBlock(vBlock));
  end;
end;

procedure TsgDXFDimensionStyle.SetCLRD(const Value: TsgColorCAD);
begin
  GetActualStyle(vnDIMCLRD, True).FDimProps.ClrD := Value;
end;

procedure TsgDXFDimensionStyle.SetCLRE(const Value: TsgColorCAD);
begin
  GetActualStyle(vnDIMCLRE, True).FDimProps.ClrE := Value;
end;

procedure TsgDXFDimensionStyle.SetCLRT(const Value: TsgColorCAD);
begin
  GetActualStyle(vnDIMCLRT, True).FDimProps.ClrT := Value;
end;

procedure TsgDXFDimensionStyle.SetDEC(const Value: Integer);
begin
  GetActualStyle(vnDIMDEC, True).FDimProps.Dec := Value;
end;

procedure TsgDXFDimensionStyle.SetDimArrowType1(const Value: TsgDimArrowType);
begin
  SetDimArrowType1BySah(Value, FDimProps);
  SetArrows(FDimProps.Arrows);
end;

procedure TsgDXFDimensionStyle.SetDimArrowType2(const Value: TsgDimArrowType);
begin
  SetDimArrowType2BySah(Value, FDimProps);
  SetArrows(FDimProps.Arrows);
end;

procedure TsgDXFDimensionStyle.SetDIMBLKT(const Value: TsgDimArrowType);
begin
  SetArrowTypeEx(Value, vnDIMBLK);
end;

procedure TsgDXFDimensionStyle.SetDIMBLK1T(const Value: TsgDimArrowType);
begin
  SetArrowTypeEx(Value, vnDIMBLK1);
end;

procedure TsgDXFDimensionStyle.SetDIMBLK2T(const Value: TsgDimArrowType);
begin
  SetArrowTypeEx(Value, vnDIMBLK2);
end;

procedure TsgDXFDimensionStyle.SetDIMLDRBLKT(const Value: TsgDimArrowType);
begin
  SetArrowTypeEx(Value, vnDIMLRBLK);
end;

procedure TsgDXFDimensionStyle.SetDIMBLK(const Value: TsgDXFBlock);
begin
  SetBlocks(vnDIMBLK, Value);
end;

procedure TsgDXFDimensionStyle.SetDimBlk1(const Value: TsgDXFBlock);
begin
  SetBlocks(vnDIMBLK1, Value);
end;

procedure TsgDXFDimensionStyle.SetDimBlk2(const Value: TsgDXFBlock);
begin
  SetBlocks(vnDIMBLK2, Value);
end;

procedure TsgDXFDimensionStyle.SetDIMLDRBLK(const Value: TsgDXFBlock);
begin
  SetBlocks(vnDIMLRBLK, Value);
end;

procedure TsgDXFDimensionStyle.SetDIMSAH(const Value: Boolean);
begin
  GetActualStyle(vnDIMSAH, True).FDimProps.Sah := Value;
end;

procedure TsgDXFDimensionStyle.SetDIMSD1(const Value: Boolean);
begin
  GetActualStyle(vnDIMSD1, True).FDimProps.SD1 := Value;
end;

procedure TsgDXFDimensionStyle.SetDIMSD2(const Value: Boolean);
begin
  GetActualStyle(vnDIMSD2, True).FDimProps.SD2 := Value;
end;

procedure TsgDXFDimensionStyle.SetDIMSE1(const Value: Boolean);
begin
  GetActualStyle(vnDIMSE1, True).FDimProps.SE1 := Value;
end;

procedure TsgDXFDimensionStyle.SetDIMSE2(const Value: Boolean);
begin
  GetActualStyle(vnDIMSE2, True).FDimProps.SE2 := Value;
end;

procedure TsgDXFDimensionStyle.SetDIMTIH(const Value: Boolean);
begin
  GetActualStyle(vnDIMTIH, True).FDimProps.Tih := Value;
end;

procedure TsgDXFDimensionStyle.SetDIMTOH(const Value: Boolean);
begin
  GetActualStyle(vnDIMTOH, True).FDimProps.Toh := Value;
end;

procedure TsgDXFDimensionStyle.SetEXE(const Value: TsgFloat);
begin
  GetActualStyle(vnDIMEXE, True).FDimProps.Exe := Value;
end;

procedure TsgDXFDimensionStyle.SetEXO(const Value: TsgFloat);
begin
  GetActualStyle(vnDIMEXO, True).FDimProps.Exo := Value;
end;

procedure TsgDXFDimensionStyle.SetLFAC(const Value: Double);
begin
  GetActualStyle(vnDIMLFAC, True).FDimProps.LFac := Value;
end;

procedure TsgDXFDimensionStyle.SetLWD(const Value: TsgFloat);
begin
  GetActualStyle(vnDIMLWD, True).FDimProps.LwD := Value;
end;

procedure TsgDXFDimensionStyle.SetLWE(const Value: TsgFloat);
begin
  GetActualStyle(vnDIMLWE, True).FDimProps.LwE := Value;
end;

procedure TsgDXFDimensionStyle.SetOwnerStyle(const AValue
  : TsgDXFDimensionStyle);
begin
end;

function TsgDXFDimensionStyle.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;

  procedure ToXMLNodeBlock(const AAttribName: string; const ABlk: TsgDXFBlock);
  var
    vValue: string;
  begin
    if Assigned(ABlk) then
      vValue := ABlk.Name
    else
      vValue := ''; // sgDimensionArrowTypeNames[datClosedfilled];
    ANode.AddAttribNV(AAttribName).ValueAsStr := vValue;
  end;

begin
  Result := inherited ToXMLNode(ANode, AMode);
  ToXMLNodeBlock(cnstXMLNames[xmlDimBlk].Name, FBlks[vnDIMBLK]);
  ToXMLNodeBlock(cnstXMLNames[xmlDimBlk1].Name, FBlks[vnDIMBLK1]);
  ToXMLNodeBlock(cnstXMLNames[xmlDimBlk2].Name, FBlks[vnDIMBLK2]);
  ToXMLNodeBlock(cnstXMLNames[xmlDimRBlk].Name, FBlks[vnDIMLRBLK]);
  TsgDXFSectionHeader.ToXMLNodeDimProps(FDimProps, ANode, AMode);
end;

function TsgDXFDimensionStyle.ToXMLAsProperties(const ANode: TsgNode;
  const AMode: TsgXMLModes): Integer;
begin
  if IsFullPropsOrXMLHelp(AMode) or (PropertiesInit <> []) then
  begin
    Result := ToXMLNode(ANode, AMode);
    ANode.RemoveAttributeByName(cnstXMLNames[xmlName].Name);
  end
  else
    Result := cnstXML_OK;
end;

procedure TsgDXFDimensionStyle.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FTextStyleItem);
end;

function TsgDXFDimensionStyle.FromXMLAsProperties(const ANode: TsgNodeSample;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := FromXML(ANode, AResult);
end;

procedure TsgDXFDimensionStyle.UpdateDimProps(ADimProps: TsgDimStyle);
begin
  FDimProps := ADimProps;
end;

function TsgDXFDimensionStyle.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlDimBlk:
      begin
        DIMBLKT := GetArrowTypeByName(AnsiUpperCase(ANode.ValueAsStr),
          datUndefined);
      end;
    xmlDimBlk1:
      begin
        DIMBLK1T := GetArrowTypeByName(AnsiUpperCase(ANode.ValueAsStr),
          datUndefined);
      end;
    xmlDimBlk2:
      begin
        DIMBLK2T := GetArrowTypeByName(AnsiUpperCase(ANode.ValueAsStr),
          datUndefined);
      end;
    xmlDimRBlk:
      begin
        DIMLDRBLKT := GetArrowTypeByName(AnsiUpperCase(ANode.ValueAsStr),
          datUndefined);
      end
  else
    Result := TsgDXFSectionHeader.FromXMLNodeDimProps(FDimProps, AType, ANode,
      AIsChild, AResult);
  end;
end;

procedure TsgDXFDimensionStyle.SetScale(const Value: Double);
begin
  GetActualStyle(vnDIMSCALE, True).FDimProps.Scale := Value;
end;

procedure TsgDXFDimensionStyle.SetCEN(const Value: TsgFloat);
begin
  GetActualStyle(vnDIMCEN, True).FDimProps.Cen := Value;
end;

procedure TsgDXFDimensionStyle.SetTextAlign(const Value: Integer);
begin
  case Value of
    1: // align
      begin
        DIMTIH := False;
        DIMTOH := False;
      end;
    2: // ISO
      begin
        DIMTIH := False;
        DIMTOH := True;
      end;
  else // gorizontal - default
    DIMTIH := True;
    DIMTOH := True;
  end;
end;

procedure TsgDXFDimensionStyle.SetTXT(const Value: TsgFloat);
begin
  GetActualStyle(vnDIMTXT, True).FDimProps.Txt := Value;
end;

procedure TsgDXFDimensionStyle.SetGAP(const Value: TsgFloat);
begin
  GetActualStyle(vnDIMGAP, True).FDimProps.GAP := Value;
end;

procedure TsgDXFDimensionStyle.SetTAD(const Value: TsgDimTextPosVert);
begin
  GetActualStyle(vnDIMTAD, True).FDimProps.Tad := Byte(Value);
end;

procedure TsgDXFDimensionStyle.SetTXSTY(const Value: TsgDXFStyle);
begin
  GetActualStyle(vnDIMTXSTY, True).FTextStyleItem.Item := Value;
end;

procedure TsgDXFDimensionStyle.SetTIX(const Value: Integer);
begin
  GetActualStyle(vnDIMTIX, True).FDimProps.Tix := Value;
end;

procedure TsgDXFDimensionStyle.AssignEntity(Source: TsgDXFEntity);
var
  I: TsgDimNameVal;
  vDimStyle: TsgDXFDimensionStyle absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFDimensionStyle then
  begin
    for I := Low(vDimStyle.FBlks) to High(vDimStyle.FBlks) do
      SetBlocksInternal(I, vDimStyle.FBlks[I]);
    FDimProps := vDimStyle.FDimProps;
    FTextStyleItem.Item := vDimStyle.FTextStyleItem.Item;
  end;
end;

{ TsgDXFLeader }

function TsgDXFLeader.BeginExtData(const AData: TsgCADExtendedData): Boolean;
begin
  AData.AddString(String_1001, sACADXDataAppName);
  AData.AddString(String_1000, cnstDStyle);
  AData.AddString(String_1002, '{');
  Result := True;
end;

procedure TsgDXFLeader.ClearReferences;
begin
  inherited ClearReferences;
  if Assigned(FInsert) then
    FInsert.ClearReferences;
  if GetProperties <> nil then
    GetProperties.SetOwnerStyle(nil);
  FPropertiesItem.Item := nil;
  FDimStyleItem.Item := nil;
end;

constructor TsgDXFLeader.Create;
begin
  inherited Create;
  FArrowhead := True;
  FInsert := TsgDXFInsert.Create;
  FDimStyleItem := TsgTableItem.Create;
  FPropertiesItem := TsgTableItem.Create;
end;

procedure TsgDXFLeader.DoAdditionalLine(const AHookLine, AHookLineDirectional
  : Integer; const AHookLineVector: TFPoint; const ATAD: Integer;
  const AGAP, AWidth: Double);

var
  vPLastPoint: TFPoint;
  vAdditional, vDirectional: TFPoint;
  vArrowSize: Double;
begin
  if (AHookLine <> 0) and (ATAD <= 0) then
    Exit;

  vAdditional := cnstFPointZero;

  if Self.ArrowSize = 0 then
    vArrowSize := Self.DimStyle.ArrowSize
  else
    vArrowSize := Self.ArrowSize;
  if Self.ArrowScale <> 0 then
    vArrowSize := vArrowSize * Self.ArrowScale
  else
    vArrowSize := vArrowSize * Self.DimStyle.Scale;

  vDirectional := AHookLineVector;
  if AHookLineDirectional <> 1 then
    vDirectional := PtXScalar(AHookLineVector, -1);

  if AHookLine = 0 then
  begin
    vAdditional := PtXScalar(vDirectional, vArrowSize);

    vPLastPoint := Controls.Last;
    Controls.Add(vPLastPoint);
    Controls[Controls.Count - 2] := AddFPoint(vPLastPoint, vAdditional);
  end;

  if ATAD > 0 then
  begin
    vAdditional := PtXScalar(vDirectional, -(AWidth + AGAP));

    vPLastPoint := Controls.Last;
    if Controls.Count > 1 then
    begin
      if not IsEqual(Controls[Controls.Count - 2].Y, vPLastPoint.Y) then
      begin
        Controls.Add(vPLastPoint);
      end;
    end;
    Controls.Last := AddFPoint(vPLastPoint, vAdditional)
  end;
end;

procedure TsgDXFLeader.EndExtData(const AData: TsgCADExtendedData);
begin
  AData.AddString(String_1002, '}');
end;

function TsgDXFLeader.GetArrowScale: Double;
begin
  Result := ActualDimStyle.Scale;
end;

function TsgDXFLeader.GetArrowSize: Double;
begin
  Result := ActualDimStyle.ArrowSize;
end;

procedure TsgDXFLeader.SetArrowScale(const AValue: Double);
begin
  ActualDimStyle.Scale := AValue;
end;

procedure TsgDXFLeader.SetArrowSize(AValue: Double);
begin
  if AValue >= 0 then
  begin
    ActualDimStyle.ArrowSize := AValue;
    ArrowScale := 1.0;
  end;
end;

function TsgDXFLeader.GetEntType: TsgCADEntities;
begin
  Result := ceLeader;
end;

function TsgDXFLeader.GetExtData(const AData: TsgCADExtendedData): Boolean;
begin
  BeginExtData(AData);
  AData.AddInt16(Integer_1070, 40);
  AData.AddDouble(Float_1040, ArrowScale);
  AData.AddInt16(Integer_1070, 41);
  AData.AddDouble(Float_1040, ArrowSize);
  if Assigned(FInsert.BlockRecord) then
  begin
    AData.AddInt16(Integer_1070, 341);
    AData.AddInt64(String_1005, FInsert.BlockRecord.Handle);
  end;
  EndExtData(AData);
  Result := AData.DataCount > 0;
end;

function TsgDXFLeader.GetProperties: TsgDXFDimensionStyle;
begin
  Result := TsgDXFDimensionStyle(FPropertiesItem.Item)
end;

function TsgDXFLeader.GetTextStyle: TsgDXFStyle;
begin
  Result := ActualDimStyle.TextStyle;
end;

procedure TsgDXFLeader.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
var
  Prev: Boolean;
begin
  inherited Invoke(AConverter, Proc, FinishProc);
  if Visibility and FInsert.Visibility then
  begin
    Prev := AConverter.AutoInsert;
    AConverter.AutoInsert := True;
    FInsert.Invoke(AConverter, Proc, FinishProc);
    AConverter.AutoInsert := Prev;
  end;
end;

procedure TsgDXFLeader.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(FPropertiesItem.Item) then
    FPropertiesItem.Item.Link(AConverter);
  if Assigned(DimStyle) and (DimStyle.ClassType = TsgLinkObject) then
    DimStyle := TsgDXFDimensionStyle(TsgLinkObject(DimStyle)
      .GetObject(AConverter.Sections[csDimStyles]));
  if Assigned(TextStyle) and (TextStyle.ClassType = TsgLinkObject) then
    TextStyle := TsgDXFStyle(TsgLinkObject(TextStyle)
      .GetObject(AConverter.Sections[csStyles]));
  if Assigned(DIMBLK) and (DIMBLK.ClassType = TsgLinkObject) then
    DIMBLK := TsgDXFBlock(TsgLinkObject(DIMBLK)
      .GetObject(AConverter.Sections[csBlockRecords]));
  if Assigned(DIMLDRBLK) and (DIMLDRBLK.ClassType = TsgLinkObject) then
    DIMLDRBLK := TsgDXFBlock(TsgLinkObject(DIMLDRBLK)
      .GetObject(AConverter.Sections[csBlockRecords]));
  if Assigned(DimBlk1) and (DimBlk1.ClassType = TsgLinkObject) then
    DimBlk1 := TsgDXFBlock(TsgLinkObject(DimBlk1)
      .GetObject(AConverter.Sections[csBlockRecords]));
  if Assigned(DimBlk2) and (DimBlk2.ClassType = TsgLinkObject) then
    DimBlk2 := TsgDXFBlock(TsgLinkObject(DimBlk2)
      .GetObject(AConverter.Sections[csBlockRecords]));
end;

procedure TsgDXFLeader.LoadedInternal(AConverter: TsgDXFConverter);
  function Sign(Value: Double): Double;
  begin
    if Value < 0 then
      Result := -1.0
    else
      Result := 1.0;
  end;

var
  I, vNextControl, CtrlsCnt: Integer;
  Knot: Single;
  LenLineWithArrow, vLineAngle: Double;
  Pt1, Pt2: TFPoint;
begin
  if DimStyle = nil then
    DimStyle := AConverter.DimensionStyleByName(sStandardName);
  CtrlsCnt := FControls.Count - 1;
  if CtrlsCnt < 1 then
  begin
    inherited LoadedInternal(AConverter);
    FBox := cnstBadRect; // Invisible leader
    Exit;
  end;
  vLineAngle := 0;
  Pt1 := FControls.First;
  Pt2 := FControls.Last;
  FArrowPoint := Pt1;
  FTextPoint := Pt2;
  vNextControl := 1;
  for I := 1 to CtrlsCnt do
  begin
    Pt2 := FControls[I];
    LenLineWithArrow := DistanceFPoint(FArrowPoint, Pt2);
    if LenLineWithArrow < fAccuracy then
      Continue;
    vLineAngle := Sign(FArrowPoint.Y - Pt2.Y) *
      sgFunction.Degree(SGArcCos((FArrowPoint.X - Pt2.X) / LenLineWithArrow));
    vNextControl := I;
    Break;
  end;
  if FIsSpline then
  begin
    Knot := 0.0;
    FKnots.Add(Knot);
    FKnots.Add(Knot);
    for I := 1 to CtrlsCnt do
    begin
      // Knots
      Knot := Knot + DistanceFPoint(FControls[I], FControls[I - 1]);
      FKnots.Add(Knot);
    end;
    FKnots.Add(Knot);
    FKnots.Add(Knot);
    FKnots.Add(Knot);
  end;
  inherited LoadedInternal(AConverter);
  LoadInsert(AConverter, vNextControl, vLineAngle);
end;

procedure TsgDXFLeader.LoadInsert(AConverter: TsgDXFConverter;
  NextControl: Integer; const ALineAngle: Double);
var
  vSize: Double;
begin
  FInsert.Layer := Layer;
  if not FArrowhead then
    Exit;
  vSize := ArrowSize * ArrowScale;
  FInsert.Visibility := 0.5 * DistanceFPoint(FControls[0],
    FControls[NextControl]) >= vSize;
  if not FInsert.Visibility then
    Exit;

  if (FInsert.Block = nil) and (GetDimArrowType <> datUndefined) then
  begin
    if ActualDimStyle.FBlks[vnDIMLRBLK] = nil then
      ActualDimStyle.SetArrowTypeEx(GetDimArrowType, vnDIMLRBLK);
    FInsert.Block := ActualDimStyle.FBlks[vnDIMLRBLK];
    if Assigned(FInsert.Block) and (FInsert.Block.Count = 0) and
      IsBadRect(FInsert.Block.Box) then
    begin
      GenerateArrow(AConverter, FInsert.Block, GetDimArrowType);
      Converter.Loads(FInsert.Block);
    end;
  end;

  FInsert.Angle := ALineAngle;
  FInsert.Scale := MakeFPoint(vSize, vSize, vSize);
  FInsert.ColorCAD := ColorCAD;
  FInsert.Point := FArrowPoint;
  FInsert.Loaded(AConverter);
  UnionFRect(FBox, FInsert.Box);
end;

procedure TsgDXFLeader.SetColorCAD(const Value: TsgColorCAD);
begin
  inherited SetColorCAD(Value);
  FInsert.ColorCAD := Value;
end;

procedure TsgDXFLeader.SetConverter(const AConverter: TsgDXFConverter);
begin
  inherited SetConverter(AConverter);
  if Assigned(FPropertiesItem.Item) then
    FPropertiesItem.Item.SetConverter(AConverter); // for SetArrowTypeEx();
end;

procedure TsgDXFLeader.SetDimArrowType(const AValue: TsgDimArrowType);
begin
  ActualDimStyle.SetDIMLDRBLKT(AValue);
end;

procedure TsgDXFLeader.SetDIMBLK(const AValue: TsgDXFBlock);
begin
  ActualDimStyle.DIMBLK := AValue;
end;

procedure TsgDXFLeader.SetDimBlk1(const AValue: TsgDXFBlock);
begin
  ActualDimStyle.DimBlk1 := AValue;
end;

procedure TsgDXFLeader.SetDimBlk2(const AValue: TsgDXFBlock);
begin
  ActualDimStyle.DimBlk2 := AValue;
end;

procedure TsgDXFLeader.SetDIMLDRBLK(const AValue: TsgDXFBlock);
begin
  ActualDimStyle.DIMLDRBLK := AValue;
  FInsert.Block := nil;
end;

procedure TsgDXFLeader.SetDimStyle(const AValue: TsgDXFDimensionStyle);
begin
  FDimStyleItem.Item := AValue;
  if Assigned(FPropertiesItem.Item) then
    TsgDXFDimensionStyle(FPropertiesItem.Item)
      .SetOwnerStyle(TsgDXFDimensionStyle(FDimStyleItem.Item));
end;

procedure TsgDXFLeader.SetDimStyleInternal(const AValue: TsgDXFDimensionStyle);
begin
  if FPropertiesItem.Item <> nil then
    if TsgDXFDimensionProperties(FPropertiesItem.Item)
      .OwnerStyle = FDimStyleItem.Item then
      TsgDXFDimensionProperties(FPropertiesItem.Item).OwnerStyle := nil;
  FDimStyleItem.Item := AValue;
end;

procedure TsgDXFLeader.SetTextStyle(const AValue: TsgDXFStyle);
begin
  ActualDimStyle.TextStyle := AValue;
end;

procedure TsgDXFLeader.SetVisibility(const Value: Boolean);
begin
  inherited SetVisibility(Value);
  if FInsert <> nil then
    FInsert.SetVisibility(Value);
end;

function TsgDXFLeader.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlArrowhead].Name).ValueAsBool := Arrowhead;
  if IsXMLHelp(AMode) then
    ANode.AddAttribNV(cnstXMLNames[xmlDimStyle].Name)
  else if Assigned(DimStyle) then
    ANode.AddAttribNV(cnstXMLNames[xmlDimStyle].Name).ValueAsStr :=
      DimStyle.Name;
  ANode.AddAttribNV(cnstXMLNames[xmlLeaderPathType].Name).ValueAsInt :=
    Integer(FIsSpline);
  if IsXMLHelp(AMode) then
    ANode.AddChildNV(cnstXMLNames[xmlProperties].Name)
  else if Assigned(Properties) then
    Properties.ToXMLAsProperties
      (ANode.AddChildNV(cnstXMLNames[xmlProperties].Name), AMode);
  // RemoveProperty(Result, TsgDegree);
  // RemoveProperty(Result, TsgFPoint);
  // RemoveProperty(Result, TsgControlPoints);
  // RemoveProperty(Result, TsgFitPoints);
  // RemoveProperty(Result, TsgKnots);
  // RemoveProperty(Result, TsgWeights);
  // RemoveProperty(Result, TsgStartTangentVector);
  // RemoveProperty(Result, TsgEndTangentVector);
  ANode.AddAttribNV(cnstXMLNames[xmlArrowType].Name).ValueAsInt := ArrowType;
  ANode.AddAttribNV(cnstXMLNames[xmlArrowSize].Name).ValueAsDouble := ArrowSize;
end;

procedure TsgDXFLeader.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FInsert);
  FreeAndNil(FPropertiesItem);
  FreeAndNil(FDimStyleItem);
end;

function TsgDXFLeader.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  vStyle: TsgDXFDimensionStyle;
  vArrowType: Integer;
  vArrowSize: Double;
  vPropertiesInit: TsgDimNameVals;

  function GetDimStyle(const ANode: TsgNodeSample): TsgDXFDimensionStyle;
  begin
    if IsHandleStr(ANode.Value) then
      Result := TsgDXFDimensionStyle(Converter.Sections[csDimStyles]
        .FindEntByHandle(ANode.ValueAsHandle))
    else
      Result := TsgDXFDimensionStyle(Converter.Sections[csDimStyles]
        .FindEntByName(ANode.Value));
  end;

begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  if (not Assigned(DimStyle)) and Assigned(Converter) then
    DimStyle := Converter.DimensionStyleByName
      (Converter.HeadVarStruct.DimStyle);
  case AType.ID of
    xmlArrowType:
      begin
        vArrowType := ANode.ValueAsInt;
        if (vArrowType >= Integer(Low(TsgDimArrowType))) and
          (vArrowType <= Integer(High(TsgDimArrowType))) and
          (ArrowType <> vArrowType) then
          ArrowType := vArrowType;
      end;
    xmlArrowSize:
      ArrowSize := ANode.ValueAsDouble;
    xmlArrowhead:
      Arrowhead := ANode.ValueAsBool;
    xmlDimStyle:
      begin
        vStyle := GetDimStyle(ANode);
        if Assigned(vStyle) then
        begin
          vArrowType := ArrowType;
          vArrowSize := ArrowSize;
          try
            vPropertiesInit := [];
            if Assigned(Properties) then
              vPropertiesInit := Properties.PropertiesInit;
            DimStyle := vStyle; // set owner in SetDimtyle
          finally
            if vnDIMLRBLK in vPropertiesInit then
              ArrowType := vArrowType;
            if vnDIMASZ in vPropertiesInit then
              ArrowSize := vArrowSize;
          end;
        end;
      end;
    xmlLeaderPathType:
      FIsSpline := ANode.ValueAsInt <> 0;
    xmlProperties:
      begin
        if (ActualDimStyle.OwnerStyle = nil) or
          (ActualDimStyle.PropertiesInit = []) then
          ActualDimStyle.SetOwnerStyle(DimStyle);
        Properties.FromXMLAsProperties(ANode, AResult);
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFLeader.GetActualDimStyle: TsgDXFDimensionStyle;
begin
  if FPropertiesItem.Item = nil then
  begin
    FPropertiesItem.Item := TsgDXFDimensionProperties.Create;
    FPropertiesItem.Item.SetConverter(Converter);
    GetProperties.SetOwnerStyle(DimStyle);
  end;
  Result := GetProperties;
end;

procedure TsgDXFLeader.AssignEntity(Source: TsgDXFEntity);
var
  vLeader: TsgDXFLeader absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFLeader then
  begin
    FInsert.Block := nil;
    FArrowhead := vLeader.Arrowhead;
    DimStyle := vLeader.DimStyle;
    FIsSpline := vLeader.FIsSpline;
    if vLeader.Properties <> nil then
      ActualDimStyle.AssignEntity(vLeader.Properties)
    else
    begin
      if Assigned(FPropertiesItem.Item) then
        Properties.SetOwnerStyle(nil);
      FPropertiesItem.Item := nil;
    end;
  end;
end;

function TsgDXFLeader.GetArrowType: Byte;
begin
  Result := GetArrowByte(GetDimArrowType);
end;

function TsgDXFLeader.GetDimArrowType: TsgDimArrowType;
begin
  Result := ActualDimStyle.GetDIMLDRBLKT;
end;

function TsgDXFLeader.GetDIMBLK: TsgDXFBlock;
begin
  Result := ActualDimStyle.DIMBLK;
end;

function TsgDXFLeader.GetDimBlk1: TsgDXFBlock;
begin
  Result := ActualDimStyle.DimBlk1;
end;

function TsgDXFLeader.GetDimBlk2: TsgDXFBlock;
begin
  Result := ActualDimStyle.DimBlk2;
end;

function TsgDXFLeader.GetDIMLDRBLK: TsgDXFBlock;
begin
  Result := ActualDimStyle.DIMLDRBLK;
end;

function TsgDXFLeader.GetDimStyle: TsgDXFDimensionStyle;
begin
  Result := TsgDXFDimensionStyle(FDimStyleItem.Item);
end;

procedure TsgDXFLeader.SetArrowType(const AValue: Byte);
begin
  SetDimArrowType(sgConsts.GetArrowType(AValue));
end;

{ TsgDXFShape }

procedure TsgDXFShape.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFShape then
  begin
    FShapeName := TsgDXFShape(Source).ShapeName;
    FShapeNumber := TsgDXFShape(Source).FShapeNumber;
  end;
end;

constructor TsgDXFShape.Create;
begin
  inherited Create;
  Properties.FFontName := '';
  WinFont := False;
  FShapeName := '';
  FShapeNumber := 0;
end;

function TsgDXFShape.GetAnsiText(const AText: string; ACodePage: Integer)
  : sgRawByteString;
{$IFDEF SGDEL_2009}
var
  I: Integer;
{$ENDIF}
begin
{$IFDEF SGDEL_2009}
  Result := '';
  for I := 1 to Length(AText) do
    Result := Result + AnsiChar(Ord(AText[I]));
{$ELSE}
  Result := inherited GetAnsiText(AText, ACodePage);
{$ENDIF}
end;

function TsgDXFShape.GetEntType: TsgCADEntities;
begin
  Result := ceShape;
end;

function TsgDXFShape.GetIsEmpty: Boolean;
begin
  Result := (Text = '');
end;

function TsgDXFShape.GetShapeName: string;
begin
  Result := FShapeName;
end;

function TsgDXFShape.GetShapeNumber: Word;
begin
  Result := FShapeNumber;
end;

function TsgDXFShape.GetSHXFont: string;
begin
  if Style <> nil then
    Result := AnsiUpperCase(Style.GetPrimaryFontName)
  else
    Result := inherited GetSHXFont;
  // if Result = '' then
  // Result := 'LTYPESHP.SHX';
end;

procedure TsgDXFShape.LoadedInternal(AConverter: TsgDXFConverter);
var
  vList: TList;
  vFontParams: TsgFontParams;
  vSHXFont: string;
begin
  FBox := cnstBadRect;
  FStartPoint := Point;
  FMatrix := cnstIdentityMat;
  // Change in future versions (SHAPE style don't have the name)
  // if FStyle = nil then
  // SetStyle(AConverter.StyleByName(sTextStyleStandardName));
  if ObliqueAngle <> 0 then
  begin
    try
      FMatrix.M[1, 0] := Tan(Radian(ObliqueAngle)) / Scale;
    except
      FMatrix := cnstIdentityMat;
    end;
  end;
  vSHXFont := '';
  if Style <> nil then
    vSHXFont := AnsiUpperCase(Style.PrimaryFont);
  FindShape(AConverter.FSHXFonts, FShapeNumber, FShapeName, vSHXFont);
  SetSHXFont(vSHXFont);
  if FShapeNumber <> 0 then
    Text := Char(FShapeNumber);
  FSHXText := Text;
  if Properties.FFontName <> '' then
  begin
    vList := TList.Create;
    try
      FillChar(vFontParams, SizeOf(TsgFontParams), 0);
      GetSHXLines(FSHXText, '', AConverter.CodePage, AConverter.FSHXFonts,
        vList, vFontParams);
      if vList.Count <> 0 then
      begin
        GetSHXBox(FSHXText, '', AConverter.CodePage, AConverter.FSHXFonts,
          vFontParams);
        FBox := MakeFRect(vFontParams.Left, vFontParams.Top, 0,
          vFontParams.Right, vFontParams.Bottom, 0);
        FMatrix := FMatXMat(FMatrix, StdMat(MakeFPoint(Height * Scale, Height,
          1), cnstFPointZero));
        FMatrix := FMatXMat(FMatrix, MatFromExtr(Extrusion, Rotation));
        FMatrix := FMatXMat(FMatrix, StdMat(cnstFPointSingle, FStartPoint));
        TransRectCorners(FBox, FMatrix);
      end;
    finally
      ClearRecordList(vList);
      vList.Free;
    end;
  end;
end;

procedure TsgDXFShape.SetShapeName(const Value: string);
begin
  FShapeName := Value;
end;

procedure TsgDXFShape.SetShapeNumber(const Value: Word);
begin
  FShapeNumber := Value;
end;

{ TsgDXFText }

constructor TsgDXFText.Create;
begin
  inherited Create;
  FBox := cnstBadRect;
  FFont := TmvExtFont.Create;
  FPropertiesItem := TsgTableItem.Create;
  FPropertiesItem.Item := TsgDXFStyle.Create;
  Properties.FFontName := 'Arial';
  FFont.Name := Properties.FFontName;
  FFont.Color := ConvertColorCADToRGB(FColor);
  FExtrusion := cnstExtrusion;
  FTextStyleItem := TsgStyleItem.Create;
  TsgStyleItem(FTextStyleItem).NotifyChange := StyleChanged;
  WinFont := True;
end;

procedure TsgDXFText.ApplyStyle(const AStyle: TsgDXFStyle);
begin
  if Style <> AStyle then
    Style := AStyle
  else
    ApplyStyleProps(Style);
end;

procedure TsgDXFText.ApplyStyleProps(const AStyle: TsgDXFStyle);
begin
  if Assigned(AStyle) and (AStyle.ClassType <> TsgLinkObject) then
  begin
    ObliqueAngle := AStyle.ObliqueAngle;
    Scale := AStyle.WidthFactor;
    if not InsideMText then
      if AStyle.FixedHeight <> 0 then
        Height := AStyle.FixedHeight
  end;
end;

procedure TsgDXFText.StyleChanged(Sender: TObject);
begin
  if Assigned(Style) then
    ApplyStyleProps(Style);
end;

procedure TsgDXFText.CreateTextParse;
begin
  if FTextParse = nil then
    New(FTextParse);
  FTextParse^ := cnstTextParseZero;
end;

procedure TsgDXFText.AssignEntity(Source: TsgDXFEntity);
var
  vText: TsgDXFText absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFText then
  begin
    Style := vText.Style;
    FExtrusion := vText.FExtrusion;
    FFont.Assign(vText.FFont);
    FHAlign := vText.FHAlign;
    Properties := vText.Properties;
    FInternalFlags := vText.FInternalFlags;
    FMatrix := vText.FMatrix;
    if FMText <> nil then
    begin
      FMText.Free;
      FMText := nil;
    end;
    Point1 := vText.Point1;
    FRotation := vText.FRotation;
    FSHXText := '';
    FSHXUnicodeText := '';
    FText := vText.Text;
    FLineWeight := vText.FLineWeight;
    FUnicodeText := '';
    FVAlign := vText.FVAlign;
  end;
end;

function TsgDXFText.HasSecond: Boolean;
// is the second alignment point must be used
begin
  Result := (Point1.X <> cnstIllegal) and (Point1.Y <> cnstIllegal);
end;

function TsgDXFText.GetHeight: TsgFloat;
begin
  Result := Properties.FixedHeight;
end;

procedure TsgDXFText.SetHeight(AValue: TsgFloat);
begin
  Properties.FixedHeight := AValue;
end;

function TsgDXFText.GetPoint1: TFPoint;
begin
  Result := FPoint1;
end;

function TsgDXFText.GetProperties: TsgDXFStyle;
begin
  Result := TsgDXFStyle(FPropertiesItem.Item);
end;

procedure TsgDXFText.SetPoint1(AValue: TFPoint);
begin
  FPoint1 := AValue;
end;

procedure TsgDXFText.SetProperties(const Value: TsgDXFStyle);
begin
  Properties.AssignEntity(Value);
end;

function TsgDXFText.GetRotation: Single;
begin
  Result := FRotation;
end;

procedure TsgDXFText.SetRotation(AValue: Single);
begin
  FRotation := AValue;
end;

function TsgDXFText.GetStyle: TsgDXFStyle;
begin
  Result := TsgDXFStyle(FTextStyleItem.Item);
end;

function TsgDXFText.GetBox: TFRect;
begin
  Result := FBox;
end;

function TsgDXFText.EntName: string;
begin
  Result := inherited EntName + ' ' + FText;
end;

function TsgDXFText.IsNotSetFontName: Boolean;
begin
  Result := not(itfSetFontName in FInternalFlags);
end;

function TsgDXFText.IsOnePixelOptimisationValid: Boolean; // evg
begin
  Result := not(IsEmpty or (Scale = 0));
end;

procedure TsgDXFText.SetOblique(Value: Single);
var
  vObliqueAngle: Double;
begin
  vObliqueAngle := Value - Floor(Value / 180) * 180;
  if Abs(vObliqueAngle) = 90 then
    vObliqueAngle := 0;
  Properties.ObliqueAngle := vObliqueAngle;
end;

procedure TsgDXFText.SetTextValue(const Value: string);
begin
  FText := SetTextStr(Value);
  FUnicodeText := ''; // read only variable
end;

procedure TsgDXFText.SetUpsideDown(const Value: Boolean);
begin
  Properties.UpsideDown := Value;
end;

procedure TsgDXFText.SetScale(const Value: Double);
begin
  Properties.WidthFactor := Value;
end;

procedure TsgDXFText.SetSHXFont(const AFontName: string);
var
  vExt: string;
begin
  if Length(AFontName) > 0 then
  begin
    vExt := AnsiLowerCase(ExtractFileExt(AFontName));
    if (Length(vExt) = 0) or (vExt = '.shx') then
    begin
      WinFont := False;
      Properties.FFontName := Copy(AFontName, 1,
        Length(AFontName) - Length(vExt));
      Font.Name := Properties.FFontName;
    end;
  end;
end;

procedure TsgDXFText.SetStyle(AStyle: TsgDXFStyle);
begin
  FTextStyleItem.Item := AStyle;
end;

procedure TsgDXFText.SetStyleRef(const Value: TsgDXFStyle);
var
  vEvent: TNotifyEvent;
begin
  vEvent := TsgStyleItem(FTextStyleItem).NotifyChange;
  try
    TsgStyleItem(FTextStyleItem).NotifyChange := nil;
    SetStyle(Value);
  finally
    TsgStyleItem(FTextStyleItem).NotifyChange := vEvent;
  end;
end;

procedure TsgDXFText.ChangeByStyle(AStyle: TsgDXFStyle);
var
  vPos: Integer;
  vFontType: TsgFontType;
begin
  Style := AStyle;
  Properties.FFontName := Style.FontName;
  Font.Style := [];
  if Properties.FFontName <> '' then
  begin
    Font.Style := Style.FontStyle;
    vPos := Pos('.', Properties.FFontName);
    if vPos <> 0 then
    begin
      vFontType := GetFontTypeByFileNameExt(Properties.FFontName);
      if vFontType <> ftUndefined then
        SetLength(Properties.FFontName, vPos - 1);
    end;
    WinFont := True;
  end
  else
  begin
    Properties.FFontName := Style.GetPrimaryFontName;
    vFontType := GetFontTypeByFileNameExt(Properties.FFontName);
    vPos := Pos('.', Properties.FFontName);
    if vPos > 0 then
    begin
      WinFont := vFontType <> ftSHX;
      if vFontType in [ftSHX, ftUndefined] then
        SetLength(Properties.FFontName, vPos - 1);
    end
    else
      WinFont := False;
  end;
  Font.Name := Properties.FFontName;
  if Style.BigFont <> '' then // need fix GetSHXLines
    Properties.FFontName := '';
  if InsideMText then
  begin
    if ObliqueAngle = 0 then
      ObliqueAngle := Style.ObliqueAngle;
    if Scale = 1 then
      Scale := Style.FWidthFactor;
  end;
end;

procedure TsgDXFText.ClearReferences;
begin
  inherited ClearReferences;
  Style := nil;
  FPropertiesItem.Item := nil;
end;

function TsgDXFText.GetText: string;
begin
  Result := FText;
end;

function TsgDXFText.GetTextStyleInternal: Pointer;
begin
  Result := Style;
end;

procedure TsgDXFText.ApplyRotation;
begin
  if WinFont and Backward and UpsideDown then
    if FRotation > 180 then
      FRotation := FRotation - 180
    else
      FRotation := FRotation + 180;
end;

procedure TsgDXFText.GetBase(AWidth, AHeight: Extended;
  var Base, Start: TFPoint); // positioning
var
  L: Double;
  Pt: TFPoint;
begin
  if FHAlign or FVAlign = 0 then
    Base := Point
  else
    Base := Point1;
  case FHAlign of
    1, 4:
      Start.X := -AWidth / 2;
    2:
      Start.X := -AWidth;
  end;
  if (AWidth > fAccuracy) and (FHAlign in [3, 5]) then
  begin
    Base := Point;
    Pt := MakeFPoint(Point1.X - Point.X, Point1.Y - Point.Y,
      Point1.Z - Point.Z);
    L := Sqrt(Sqr(Pt.X) + Sqr(Pt.Y)) / AWidth;
    if FHAlign = 3 then
    begin
      Height := Height * L;
      AHeight := AHeight * L;
    end;
    Scale := Scale * L;
    if (FHAlign = 5) and (FVAlign = 0) then
    begin // "fit align" - needs to create a new FScale and recalculate rotation
      Rotation := 0;
      if (Pt.X <> 0) and (Pt.Y <> 0) then
        Rotation := Degree(ArcTan2(Pt.Y, Pt.X))
      else if (Pt.X = 0) and (Pt.Y <> 0) then
        Rotation := 90 + 180 * Ord(Sign(Pt.Y) = -1);
      // FScale := L;// it works only for correct width of the text (AWidth)
    end;
    ApplyRotation;
  end;
  case FVAlign of
    0:
      Start.Y := AHeight * 0.8;
    1:
      Start.Y := AHeight;
    2:
      Start.Y := AHeight / 2;
  end;
  if FHAlign = 4 then
    Start.Y := AHeight / 2;
end;

function TsgDXFText.GetMatrix: TFMatrix;
begin
  Result := FMatrix;
end;

function TsgDXFText.Expand(AWidth, AHeight, AHeightMax: Extended;
  const ASign: TFPoint): Boolean;
var
  vBase, vFitPt: TFPoint;
  L: Extended;
begin
  Result := False;
  FStartPoint := cnstFPointZero;
  if FHAlign or FVAlign = 0 then
    vBase := Point
  else
    vBase := Point1;
  case FHAlign of
    1, 4:
      FStartPoint.X := ASign.Z * AWidth * Scale / 2;
    2:
      if not((AWidth < 0) and (ASign.X > 0)) then
        FStartPoint.X := ASign.Z * AWidth * Scale;
  end;
  if (AWidth > 0) and (FHAlign in [3, 5]) then
  begin
    vBase := Point;
    vFitPt := SubFPoint(Point1, Point);
    L := Sqrt(Sqr(vFitPt.X) + Sqr(vFitPt.Y)) / AWidth;
    if FHAlign = 3 then
    begin
      Height := Height * L;
      AHeight := AHeight * L;
      L := 1;
    end
    else
    begin
      Result := True;
      Scale := Scale * L;
    end;
    if FVAlign = 0 then
    begin // "fit align" - needs to create a new FScale and recalculate rotation
      Result := True;
      Rotation := GetAngleByPoints(cnstFPointZero, vFitPt, False);
      Scale := L;
    end;
    ApplyRotation;
  end;
  case FVAlign of
    0:
      FStartPoint.Y := 0;
    1:
      FStartPoint.Y := AHeight / 3;
    2:
      FStartPoint.Y := -AHeight / 2;
    3, 4:
      FStartPoint.Y := -AHeight;
  end;
  if FHAlign = 4 then
    FStartPoint.Y := -AHeightMax / 2;
  FStartPoint := RotateFPoint(FStartPoint, Rotation);
  FStartPoint := MakeFPoint(FStartPoint.X + vBase.X,
    FStartPoint.Y + vBase.Y, vBase.Z);
  if Extruded(Extrusion) then
    DoExtrusion(FStartPoint, Extrusion);
end;

function TsgDXFText.GetScale: Double;
begin
  Result := Properties.WidthFactor;
end;

function TsgDXFText.GetSHXBox(const AStr: string; const AWStr: WideString;
  CodePage: Integer; ASHXFontsList: TsgSHXFontList;
  var AFontParams: TsgFontParams): Boolean;
var
  vSy: Double;
  vStr: sgRawByteString;
begin
  Result := False;
  vStr := GetAnsiText(AStr, CodePage);
  if (SHXFont = '') and ((Style <> nil) and (Style.FSHXStyle <> nil)) then
    GetSHXTextBoxFromStyle(ASHXFontsList, Style.FSHXStyle, vStr, AWStr,
      CodePage, False, Font.Style, AFontParams.Above, AFontParams.Below,
      AFontParams.Width, AFontParams.Height, AFontParams.Left,
      AFontParams.Bottom, AFontParams.Right, AFontParams.Top, AFontParams.After)
  else if SHXFont <> '' then
    DrawSHXTextBox(ASHXFontsList, SHXFont, vStr, AWStr, CodePage, False,
      Font.Style, AFontParams.Above, AFontParams.Below, AFontParams.Width,
      AFontParams.Height, AFontParams.Left, AFontParams.Bottom,
      AFontParams.Right, AFontParams.Top, AFontParams.After)
  else
    GetSHXTextBox(ASHXFontsList, Style.Name, vStr, AWStr, CodePage, False,
      Font.Style, AFontParams.Above, AFontParams.Below, AFontParams.Width,
      AFontParams.Height, AFontParams.Left, AFontParams.Bottom,
      AFontParams.Right, AFontParams.Top, AFontParams.After);
  if AFontParams.Above <> 0 then
    Result := True;
  if FTextParse <> nil then
  begin
    if not Result then
      AFontParams.Above := fAccuracy;
    vSy := Height / AFontParams.Above;
    FTextParse^.FontParams.Above := AFontParams.Above * vSy;
    FTextParse^.FontParams.Below := AFontParams.Below * vSy;
    FTextParse^.FontParams.Width := AFontParams.Width * vSy;
    FTextParse^.FontParams.Height := AFontParams.Height * vSy;
    FTextParse^.FontParams.Top := AFontParams.Top * vSy;
    FTextParse^.FontParams.Left := AFontParams.Left * vSy;
    FTextParse^.FontParams.Bottom := AFontParams.Bottom * vSy;
    FTextParse^.FontParams.Right := { (AFontParams.Left + AFontParams.Width) }
      AFontParams.Right * vSy;
    FTextParse^.FontParams.DX := AFontParams.After * vSy -
      FTextParse^.FontParams.Right;
    FTextParse^.FontParams.DY :=
      (FTextParse^.FontParams.Top - FTextParse^.FontParams.Above);
    if FTextParse^.FontParams.DY < fAccuracy then
      FTextParse^.FontParams.DY := 0;
  end;
end;

function TsgDXFText.GetSHXFont: string;
begin
  Result := '';
  if (not WinFont) and (Length(Properties.FFontName) > 0) then
    Result := Properties.FFontName + '.shx';
end;

procedure TsgDXFText.GetSHXLines(const AStr: string; const AWStr: WideString;
  CodePage: Integer; ASHXFontsList: TsgSHXFontList; AList: TList;
  var AFontParams: TsgFontParams);
var
  vStyleName: string;
  vStr: sgRawByteString;
  vSHXFont: string;
begin
  vStr := GetAnsiText(AStr, CodePage);
  vSHXFont := SHXFont;
  if (vSHXFont = '') and ((Style <> nil) and (Style.FSHXStyle <> nil)) then
    GetSHXTextFromStyle(ASHXFontsList, Style.FSHXStyle, vStr, AWStr, CodePage,
      False, Backward, AList, Font.Style, AFontParams.Above, AFontParams.Below,
      AFontParams.Left, AFontParams.Bottom, AFontParams.Right, AFontParams.Top)
  else if vSHXFont <> '' then
    DrawSHXText(ASHXFontsList, vSHXFont, vStr, AWStr, CodePage, False, Backward,
      AList, Font.Style, AFontParams.Above, AFontParams.Below, AFontParams.Left,
      AFontParams.Bottom, AFontParams.Right, AFontParams.Top)
  else
  begin
    if Style <> nil then
      vStyleName := Style.Name
    else
      vStyleName := '';
    GetSHXText(ASHXFontsList, vStyleName, vStr, AWStr, CodePage, AList,
      Font.Style, AFontParams.Above, AFontParams.Below, AFontParams.Left,
      AFontParams.Bottom, AFontParams.Right, AFontParams.Top);
  end;
end;

procedure AddPoint(const APts: TsgIntegerList; const AMatrix: PFMatrix;
  const V: PsgSHXVertex);
begin
  APts.Add(Round(V^.X * AMatrix^.M[0, 0] + V^.Y * AMatrix^.M[1,
    0] + AMatrix^.M[3, 0]));
  APts.Add(Round(V^.X * AMatrix^.M[0, 1] + V^.Y * AMatrix^.M[1,
    1] + AMatrix^.M[3, 1]));
end;

procedure AddSHXFPoint(const APts: TList; const AMatrix: PFMatrix;
  const V: PsgSHXVertex);
var
  P: PFPoint;
begin
  New(P);
  APts.Add(P);
  P^.X := V^.X * AMatrix^.M[0, 0] + V^.Y * AMatrix^.M[1, 0] + AMatrix^.M[3, 0];
  P^.Y := V^.X * AMatrix^.M[0, 1] + V^.Y * AMatrix^.M[1, 1] + AMatrix^.M[3, 1];
  P^.Z := V^.X * AMatrix^.M[0, 2] + V^.Y * AMatrix^.M[1, 2] + AMatrix^.M[3, 2];
end;

procedure TsgDXFText.GetSHXLinesEx(ASHXFontsList: TsgSHXFontList; AList: TList;
  const AMatrix: PFMatrix; const APolyPolyline: TsgIntegerList;
  const ACounts: TsgIntegerList; CodePage: Integer);
type
  TsgProcBySHXVertex = procedure(const APts: TList; const AMatrix: PFMatrix;
    const V: PsgSHXVertex);

var
  vMatrix: TFMatrix;
  vVertexes: TList;
  I, Cnt, vPtCntLast, vPtCnt: Integer;
  vActList: TList;
  vFontParams: TsgFontParams;
  vVertex, vVertexPrev: PsgSHXVertex;
  vSy: Double;
  // vProc: TsgProcBySHXVertex;
  vIsNotPolyPolyline: Boolean;

  procedure ProcCase(AIndex: Boolean; const AMatrix: PFMatrix;
    const V: PsgSHXVertex);
  begin
    if AIndex then
      AddSHXFPoint(vActList, AMatrix, V)
    else
      AddPoint(APolyPolyline, AMatrix, V)
  end;

  procedure AddBulge(const PV1, PV2: PsgSHXVertex);
  var
    X0, Y0, X1, Y1, A, A1, BT: Double;
    I, vNumberOfCircleParts: Integer;
    SinA, CosA: Extended;
    vSHXVertex: TsgSHXVertex;
  begin
    vNumberOfCircleParts := GetNumberOfCircleParts;
    A := ArcTan(PV1^.Bulge) * 2;
    A1 := A / (vNumberOfCircleParts) * 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 vNumberOfCircleParts - 1 do
    begin
      vSHXVertex.X := X0 + (X1 - X0) * CosA - (Y1 - Y0) * SinA;
      vSHXVertex.Y := Y0 + (X1 - X0) * SinA + (Y1 - Y0) * CosA;
      ProcCase(vIsNotPolyPolyline, @vMatrix, @vSHXVertex);
      X1 := vSHXVertex.X;
      Y1 := vSHXVertex.Y;
    end;
  end;

begin
  if (AList = nil) and (APolyPolyline = nil) then
    Exit;
  vVertexes := TList.Create;
  try
    GetSHXLines(SHXText, SHXUnicodeText, CodePage, ASHXFontsList, vVertexes,
      vFontParams);
    if vVertexes.Count > 0 then
    begin
      vPtCntLast := 0;
      if vFontParams.Above <> 0 then
      begin
        vSy := Height / vFontParams.Above;
        vMatrix := StdMat(MakeFPoint(vSy, vSy, 1), cnstFPointZero);
      end
      else
        vMatrix := cnstIdentityMat;
      vMatrix := FMatXMat(vMatrix, SHXMatrix);
      if AMatrix <> nil then
        vMatrix := FMatXMat(vMatrix, AMatrix^);
      vIsNotPolyPolyline := ACounts = nil;
      if vIsNotPolyPolyline then
      begin
        vActList := TList.Create;
        AList.Add(vActList);
        // vProc := @AddSHXFPoint
      end
      else
      begin
        // vActList := APolyPolyline;
        // vProc := @AddPoint;
        ACounts.Capacity := vVertexes.Count;
      end;
      ProcCase(vIsNotPolyPolyline, @vMatrix, vVertexes[0]);
      vVertex := nil;
      Cnt := vVertexes.Count - 1;
      for I := 1 to Cnt do
      begin
        vVertex := vVertexes.List[I];
        vVertexPrev := vVertexes.List[I - 1];
        if vVertex^.PenDown then
        begin
          if vVertex^.Bulge = 0 then
            ProcCase(vIsNotPolyPolyline, @vMatrix, vVertex)
          else
            AddBulge(vVertex, vVertexPrev);
        end
        else
        begin
          if vIsNotPolyPolyline then
          begin
            case vActList.Count of
              0:
                begin
                end;
              1:
                begin
                  Dispose(PFPoint(vActList.List[0]));
                  vActList.Count := 0;
                end;
            else
              vActList := TList.Create;
              AList.Add(vActList);
            end;
          end
          else
          begin
            vPtCnt := (APolyPolyline.Count - vPtCntLast) shr 1;
            if vPtCnt > 1 then
            begin
              ACounts.Add(vPtCnt);
              vPtCntLast := APolyPolyline.Count;
            end
            else
              APolyPolyline.Count := vPtCntLast;
          end;
          ProcCase(vIsNotPolyPolyline, @vMatrix, vVertex);
        end;
        Dispose(vVertexPrev);
      end;
      if vIsNotPolyPolyline then
      begin
        case vActList.Count of
          0:
            begin
              vActList.Free;
              AList.Delete(AList.Count - 1);
            end;
          1:
            begin
              Dispose(PFPoint(vActList.List[0]));
              vActList.Free;
              AList.Delete(AList.Count - 1);
            end;
        end;
      end
      else
      begin
        vPtCnt := (APolyPolyline.Count - vPtCntLast) shr 1;
        if vPtCnt > 1 then
          ACounts.Add(vPtCnt)
        else
          APolyPolyline.Count := vPtCntLast;
      end;
      if vVertex <> nil then
        Dispose(vVertex);
    end;
  finally
    vVertexes.Free;
  end;
end;

function TsgDXFText.GetUseDefaultFontName: Boolean;
begin
  Result := itfUseDefaultFont in FInternalFlags;
end;

procedure TsgDXFText.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(Style) and (Style.ClassType = TsgLinkObject) then
    StyleRef := TsgDXFStyle(TsgLinkObject(Style)
      .GetObject(AConverter.Sections[csStyles]));
end;

procedure TsgDXFText.LoadedInternal(AConverter: TsgDXFConverter);
var
  P, C, vIndex: Integer;
  vSy, vWidth, vMaxHeight, vScaleHeigth, vHeight: Double;
  S, vFontName: string;
  vWideStr: WideString;
  WCh: WideChar;
  vList: TList;
  vTextGlyph: TsgTextGlyph;
  vFontParams: TsgFontParams;
  vSign: TFPoint;
  vUnicodeText: WideString;
  vDiamUni, vUseDefaultFontName: Boolean;
  vFontType: TsgFontType;

  procedure ParseUnicodeText(const AText: string);
  const
    cnstMinLen = 2;
    cnstTypeU = '\U+';
    cnstTypeM = '\M+';
    cnstTypeDP = '%%';
  var
    vOff, vPosM, vPosDP, I, vLength: Integer;
    vIsUniText: Boolean;
    vText, vUpText: string;

    procedure DeletePart(const APos, AOffset: Integer);
    begin
      Delete(vText, 1, APos - 1 + cnstMinLen + AOffset);
    end;

  begin
    vText := AText;
    vIsUniText := False;
    while True do
    begin
      vUpText := AnsiUpperCase(vText);
      P := AnsiPos(cnstTypeU, vUpText);
      vPosM := AnsiPos(cnstTypeM, vUpText);
      vPosDP := AnsiPos(cnstTypeDP, vUpText);
      vOff := 0;
      if (vPosDP > 0) and ((((vPosDP < P) and (P > 0)) or (P = 0)) and
        (((vPosDP < vPosM) and (vPosM > 0)) or (vPosM = 0))) then
        P := vPosDP
      else if not((P = 0) and (vPosM = 0)) then
      begin
        vOff := 5;
        if (vPosM > 0) and (((vPosM < P) and (P > 0)) or (P = 0)) then
        begin
          P := vPosM;
          vOff := 6;
        end;
      end;
      if (P = 0) or (P > Length(vText) - (cnstMinLen + vOff - 1)) then
      begin
        if (P = 0) and vIsUniText then
          FUnicodeText := FUnicodeText + vText;
        Break;
      end;
      if vOff > 0 then // not %%
        WCh := GetSymbolFromMultibyte(AConverter,
          StringHexToIntDef(Copy(vText, P + vOff - 2, 2), 0),
          StringHexToIntDef(Copy(vText, P + vOff, 2), 0),
          StrToIntDef(Copy(vText, P + vOff - 3, 1), 0), (vOff <> 6))
      else
      begin
        S := Copy(vText, P + cnstMinLen, 3);
        vLength := Length(S);
        for I := 1 to vLength do
          if not CharInSet(S[I], ['0' .. '9']) then
          begin
            SetLength(S, I - 1); // S[I] := #0;
            Break;
          end;
        C := StrToIntDef(S, Ord('?'));
        vOff := Length(PChar(S));
        if vOff = 0 then
        begin
          FUnicodeText := FUnicodeText + Copy(vText, 1, P - 1);
          DeletePart(P, 0);
          vIsUniText := True;
          Continue;
        end;
        WCh := WideChar(C);
      end;
{$IFDEF VER100}
      FUnicodeText := FUnicodeText + Copy(vText, 1, P - 1) + WideString(WCh);
{$ELSE}
      FUnicodeText := FUnicodeText + Copy(vText, 1, P - 1) + WCh;
{$ENDIF}
      DeletePart(P, vOff);
      vIsUniText := True;
    end;
  end;

  procedure InitializeParams;
  begin
    if UpsideDown then
      vSign.Y := -1
    else
      vSign.Y := 1;
    case Byte(Style.Backward) shl 1 + Byte(Backward) of
      0:
        begin
          vSign.X := 1;
          vSign.Z := -1;
        end;
      2:
        begin
          vSign.X := -1;
          vSign.Z := 1;
        end;
    else
      begin
        vSign.X := -1;
        vSign.Z := -1;
      end;
    end;
    if UpsideDown then
      vMaxHeight := (2 * FBox.Bottom - FBox.Top)
    else
      vMaxHeight := (FBox.Bottom + FBox.Top);
    FMatrix := cnstIdentityMat;
    if not Converter.IsCrossoverMatrix then
      FMatrix := StdMat(MakeFPoint(1, -1, 1), cnstFPointZero);
    if ObliqueAngle <> 0 then
    begin
      try
        FMatrix.M[1, 0] := Tan(Radian(ObliqueAngle)) / Scale;
      except
        FMatrix := cnstIdentityMat;
      end;
    end;
  end;

begin
  inherited LoadedInternal(AConverter);
  if FMText <> nil then
  begin
    FMText.Free;
    FMText := nil;
  end;
  if (FTextParse <> nil) and (FTextParse^.TwiddleCount > 0) then
  begin
    FText := StringOfChar('.', FTextParse^.TwiddleCount);
    FUnicodeText := '';
  end;
  SetDefaulParams(AConverter);
  if not InsideMText then
  begin
    FUnicodeText := '';
    if IsNotSetFontName then
      ChangeByStyle(Style);
  end;
  if AConverter.CheckUnicode then
  begin
    ReplaceAnsi(FText, '%%127', cnstQuestionMark);
    ReplaceAnsi(FText, '%%128', cnstEuro);
    ReplaceAnsi(FText, '%%176', cnstDegree);
    ReplaceAnsi(FText, '%%179', cnstQuestionMark);
    ReplaceAnsi(FText, '%%220', 'U');
    vDiamUni := (AnsiPos(cnstDiameterArialUni, Text) <> 0) or
      (AnsiPos(cnstDiameterUni, Text) <> 0);
  end
  else
    vDiamUni := False;
  if { Extruded(Extrusion) or } vDiamUni or
    (not InsideMText and ((AnsiPos('%%U', AnsiUpperCase(Text)) <> 0) or
    (AnsiPos('%%O', AnsiUpperCase(Text)) <> 0))) then
  begin
    ApplyRotation;
    FMText := TsgDXFMText.Create;
    AConverter.DoCreate(FMText);
    FMText.Visibility := Visibility;
    FMText.Style := Style;
    if Style.FWidthFactor <> XScale then
      FMText.Scale := MakeFPoint(XScale, 1, 1);
    DoExtrusion(FPoint, Extrusion);
    FMText.FPoint := FPoint;
    FMText.Extrusion := Extrusion;
    FMText.SetAngle(Rotation);
    FMText.ColorCAD := ColorCAD;
    FMText.FHeight := Height;
    FMText.FAlign := 10; // 7 in previous version
    FMText.FText := Text;
    ReplaceEvenUnEven(FMText.FText, '%%u', '\L', '\l');
    ReplaceEvenUnEven(FMText.FText, '%%o', '\O', '\o');
    FMText.Layer := Layer;
    FMText.FLineWeight := FLineWeight;
    FMText.Loaded(AConverter);
    FBox := FMText.FBox;
    Exit;
  end;
  if not InsideMText then
    ParseUnicodeText(FText);
{$IFDEF SGDEL_2009}
  if FUnicodeText = '' then
    FUnicodeText := FText;
{$ENDIF}
  if not HasSecond then
  begin
    FHAlign := 0;
    FVAlign := 0;
  end;
  if Layer = nil then
    Layer := AConverter.LayerByName('0');
  FBox := BadRect;
  if ((Text = '') and (UnicodeText = '')) or ((not InsideMText) and IsEmpty)
  then
    Exit;
  if Assigned(Style) and (not WinFont) and AConverter.UseSHXFonts then
  begin
    S := Text;
    vFontName := SHXFont;
    if vFontName = '' then
      vFontName := Style.GetPrimaryFontName;
    FillChar(vFontParams, SizeOf(TsgFontParams), 0);
    FSHXText := S;
    vWideStr := '';
    if IsUnicodeSHX(AConverter.FSHXFonts, Style.FSHXStyle, vFontName) or
      (Style.BigFont <> '') then
    begin
      if (S = '�') and (Font.Name = 'Symbol') then
        vWideStr := WideChar(8709)
      else
        vWideStr := FUnicodeText;
{$IFNDEF SGDEL_2009}
      if (Style.BigFont = '') and (vWideStr = '') then
        if AConverter.CodePage <> 0 then
        begin
          vWideStr := StrToUnicode(AConverter.CodePage, S);
          if vWideStr = '' then
            vWideStr := ConvertToWideString(S, AConverter.CodePage);
        end
        else
          vWideStr := ConvertToWideString(S, AConverter.CodePage);
{$ENDIF}
    end
    else if FUnicodeText <> '' then
    begin
      // FSHXText := FUnicodeText;
      C := Length(FUnicodeText);
      SetLength(FSHXText, C);
      for P := 1 to C do
        FSHXText[P] := Char(FUnicodeText[P]);
      FSHXUnicodeText := '';
    end;
    if vWideStr <> '' then
    begin
      FSHXText := '';
      FSHXUnicodeText := vWideStr;
    end;
    vList := TList.Create;
    try
      GetSHXLines(SHXText, SHXUnicodeText, AConverter.CodePage,
        AConverter.FSHXFonts, vList, vFontParams);
      if (vList.Count <> 0) and (vFontParams.Above <> 0) then
      begin
        if GetSHXBox(SHXText, SHXUnicodeText, AConverter.CodePage,
          AConverter.FSHXFonts, vFontParams) then
        begin
          vSy := Height / vFontParams.Above;
          FBox := MakeFRect(vFontParams.Left * vSy, vFontParams.Top * vSy, 0,
            vFontParams.Right * vSy, vFontParams.Bottom * vSy, 0);
          InitializeParams;
          if Expand(vFontParams.Width * vSy * vSign.X, Height * vSign.Y,
            vMaxHeight, vSign) then
            InitializeParams;
          FMatrix := FMatXMat(FMatrix, StdMat(MakeFPoint(Scale, 1, 1),
            cnstFPointZero));
          FMatrix := FMatXMat(FMatrix, MatFromExtr(Extrusion,
            vSign.X * vSign.Y * FRotation));
          FMatrix := FMatXMat(FMatrix, StdMat(MakeFPoint(vSign.X, vSign.Y, 1),
            FStartPoint));
          TransRectCorners(FBox, FMatrix);
        end;
      end;
    finally
      ClearRecordList(vList);
      vList.Free;
    end;
  end;
  if WinFont or IsBadRect(FBox) then // Box for TrueType Fonts
  begin
{$IFNDEF SGDEL_2009}
    if (FUnicodeText = '') and not((FText = '�') and (Font.Name = 'Symbol'))
    then
    begin
      if AConverter.CodePage <> 0 then
      begin
        FUnicodeText := StrToUnicode(AConverter.CodePage, FText);
        if FUnicodeText = '' then
          FUnicodeText := ConvertToWideString(FText, AConverter.CodePage);
      end
      else
        FUnicodeText := ConvertToWideString(FText, AConverter.CodePage);
      { FUnicodeText := AConverter.ConvertToCodePage(FText);
        if Length(FUnicodeText) = Length(FText) then
        begin
        FText := FUnicodeText;
        FUnicodeText := '';
        end; }
    end;
{$ENDIF}
    // imImport - nonunicode import mode
    if AConverter.CheckUnicode and (FUnicodeText <> '') then
    begin
{$IFNDEF UNICODE}
      if FUnicodeText <> wcDiameterUni then
        FText := ''
      else
{$ENDIF}
      begin
        FText := string(FUnicodeText);
        FUnicodeText := '';
      end;
    end;
    if InsideMText or (Style.FontName = '') then
    begin
      vUseDefaultFontName := UseDefaultFontName;
      if InsideMText then
        vFontName := Font.Name
      else
        vFontName := Style.GetPrimaryFontName;

      if (Length(vFontName) > 0) then
      begin
        vFontType := GetFontTypeByFileNameExt(vFontName);
        case vFontType of
          ftTTF, ftTTC:
            begin
              vFontName := GetFontNameByFileName(vFontName);
              if Length(vFontName) > 0 then
              begin
                Font.Style := GetFontStyleByFontName(vFontName);
                if (not InsideMText) and (Length(Style.FontName) > 0) then
                  vFontName := Style.FontName
                else
                  vFontName := GetFontNameWithoutStyle(vFontName);
              end
              else
                vFontName := Style.FontName;
            end;
          ftFON:
            vUseDefaultFontName := True;
        else
          if InsideMText then
          begin
            if IsSystemNotRasterFontEx(vFontName) <> 1 then
              vUseDefaultFontName := True;
          end
          else
          begin
            if vFontType = ftSHX then
              SetLength(vFontName, Length(vFontName) - 4);
            if IsNotTTFFont(vFontName) then
              vUseDefaultFontName := True;
          end;
        end;
      end
      else
        vUseDefaultFontName := True;
      UseDefaultFontName := vUseDefaultFontName;
      if vUseDefaultFontName then
        Font.Name := AConverter.DoFindFont(Self, False, vFontName)
      else
        Font.Name := vFontName;
    end;
    if (Style.BigFont <> '') and (FUnicodeText <> '') then
      Font.Name := AConverter.DoFindFont(Self, True, vFontName);
    // only for big fonts
    Converter.FCanvas.Font := Font;
    Converter.FCanvas.Font.Name := Font.Name;

    if Length(FUnicodeText) > 0 then
    begin
      vIndex := WideStrScan(FUnicodeText, wcDiameterUni);
      if vIndex > 0 then
      begin
        if not SymbolExistFont(Font, Word(wcDiameterUni)) then
        begin
          repeat
            FUnicodeText[vIndex] := wcDiametr;
            vIndex := WideStrScan(FUnicodeText, wcDiameterUni);
          until vIndex < 1;
        end;
      end;
    end;

    if Length(FText) > 0 then
    begin
      vIndex := AnsiPos('^ ', FText);
      while vIndex > 0 do
      begin
        Delete(FText, vIndex + 1, 1);
        vIndex := AnsiPos('^ ', FText);
      end;
    end;
    if Win32Platform = VER_PLATFORM_WIN32_NT then
      vUnicodeText := FUnicodeText
    else
    begin
      vUnicodeText := '';
      if Length(FUnicodeText) > 0 then
        FText := string(FUnicodeText);
    end;
    vIndex := ContainerOfTextGlyphs.IndexOf(Font.Name,
      Converter.FCanvas.Font.Style);
    if vIndex > -1 then
      vTextGlyph := ContainerOfTextGlyphs.TextGlyph[vIndex]
    else
      vTextGlyph := ContainerOfTextGlyphs.AddTextGlyphsByFont(Font);
    vTextGlyph.LoadedW(Text, vUnicodeText, Converter.FCanvas.Font);
    vScaleHeigth := Height * vTextGlyph.HKoef / cnstHeigthDef;
    InitializeParams;
    FMatrix := FMatXMat(FMatrix, StdMat(MakeFPoint(Scale * vScaleHeigth,
      vScaleHeigth, 1), cnstFPointZero));
    FBox := vTextGlyph.GetBoxW(Text, vUnicodeText, @FMatrix, nil);
    vWidth := FBox.Right - FBox.Left; // vHeight := FBox.Top - FBox.Bottom;
    if Abs(Scale) > fAccuracy then
      vWidth := vWidth / Scale;
    vHeight := Height;
    if Expand(vSign.X * vWidth, vSign.Y * Height, Height, vSign) then
    begin
      InitializeParams;
      FMatrix := FMatXMat(FMatrix, StdMat(MakeFPoint(Scale * vScaleHeigth,
        vScaleHeigth, 1), cnstFPointZero));
    end;
    if (vHeight <> Height) and (Height <> 0) then
      FMatrix := FMatXMat(FMatrix, FMatByScale(Height / vHeight));
    FMatrix := FMatXMat(FMatrix, MatFromExtr(Extrusion,
      vSign.X * vSign.Y * Rotation));
    FMatrix := FMatXMat(FMatrix, StdMat(MakeFPoint(vSign.X, vSign.Y, 1),
      FStartPoint));
    if FTextParse <> nil then
      FBox := vTextGlyph.GetBoxW(Text, vUnicodeText, @FMatrix,
        @FTextParse^.FontParams)
    else
      FBox := vTextGlyph.GetBoxW(Text, vUnicodeText, @FMatrix, nil);
  end;
  if (FTextParse <> nil) and (FTextParse^.TwiddleCount > 0) then
  begin
    if LongWord(Length(FText)) < FTextParse^.TwiddleCount then
      SetLength(FText, FTextParse^.TwiddleCount);
    StrPCopy(PChar(FText), StringOfChar(' ', FTextParse^.TwiddleCount));
    FUnicodeText := '';
  end;
end;

procedure TsgDXFText.DoNewText(const ANewText: string);
begin
  if Assigned(Converter) then
  begin
    if not(CompareStr(FText, ANewText) = 0) then
    begin
      FText := ANewText;
      Self.Loaded(Converter);
    end;
  end;
end;

procedure TsgDXFText.SetBackward(const AValue: Boolean);
begin
  Properties.Backward := AValue;
end;

procedure TsgDXFText.SetColorCAD(const Value: TsgColorCAD);
begin
  inherited SetColorCAD(Value);
  FFont.Color := ConvertColorCADToRGB(FColor);
end;

procedure TsgDXFText.SetDefaulParams(AConverter: TsgDXFConverter);
begin
  if Height <= 0 then // for default value as autocad
    Height := AConverter.HeadVarStruct.TextSize;
  // WinFont := True;
  if Style = nil then
    SetStyle(AConverter.StyleByName(sStandardName));
end;

procedure TsgDXFText.SetExtrusion(const Value: TFPoint);
begin
  FExtrusion := Value;
end;

procedure TsgDXFText.SetFontName(const AFontName: string);
var
  vFontType: TsgFontType;
  vFileName: string;
begin
  if Length(AFontName) > 0 then
  begin
    Include(FInternalFlags, itfSetFontName);
    vFontType := GetFontTypeByFileNameExt(AFontName);
    case vFontType of
      ftUndefined:
        begin
          vFileName := GetFileNameByFontName(AFontName);
          if vFileName <> '' then
            SetTTFFont(AFontName)
          else
            SetSHXFont(AFontName);
        end;
      ftTTF, ftTTC, ftFON:
        SetTTFFont(AFontName);
    else
      SetSHXFont(AFontName);
    end;
  end
  else
    Exclude(FInternalFlags, itfSetFontName);
end;

procedure TsgDXFText.SetInsideMText(const AValue: Boolean);
begin
  SetInternalFlag(itfInsideMText, AValue);
end;

procedure TsgDXFText.SetInternalFlag(const AInternalFlag: TsgInternalTextFlag;
  const AValue: Boolean);
begin
  if AValue then
    Include(FInternalFlags, AInternalFlag)
  else
    Exclude(FInternalFlags, AInternalFlag);
end;

procedure TsgDXFText.SetInternalTextFlags(const AValue: TsgInternalTextFlags);
begin
  FInternalFlags := AValue;
end;

procedure TsgDXFText.SetLineWeight(Value: Double);
begin
  FLineWeight := Value;
end;

procedure TsgDXFText.SetIsSHXFont(const AValue: Boolean);
begin
  WinFont := not AValue;
end;

procedure TsgDXFText.SetUseDefaultFontName(const AValue: Boolean);
begin
  SetInternalFlag(itfUseDefaultFont, AValue);
end;

procedure TsgDXFText.SetTTFFont(const AFontName: string);
var
  vFontType: TsgFontType;
begin
  if Length(AFontName) > 0 then
  begin
    vFontType := GetFontTypeByFileNameExt(AFontName);
    if vFontType <> ftSHX then
    begin
      WinFont := True;
      if vFontType <> ftUndefined then
        Properties.FFontName := GetFontNameByFileName(AFontName)
      else
        Properties.FFontName := AFontName;
      Font.Name := Properties.FFontName;
    end;
  end;
end;

procedure TsgDXFText.SetWinFont(const AValue: Boolean);
begin
  SetInternalFlag(itfWinFont, AValue);
end;

procedure TsgDXFText.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
begin
  if not IsInvoke(AConverter) then
    Exit;
  if MText = nil then
    Proc(Self)
  else
    MText.Invoke(AConverter, Proc, FinishProc);
end;

procedure TsgDXFText.SetGeneration(const Value: Byte);
begin
  Properties.TextGenFlags := Value;
end;

function TsgDXFText.GetAnsiText(const AText: string; ACodePage: Integer)
  : sgRawByteString;
begin
{$IFDEF SGDEL_2009}
  Result := ConvertToAnsiString(AText, ACodePage)
{$ELSE}
  Result := AText;
{$ENDIF}
end;

function TsgDXFText.GetBackward: Boolean;
begin
  Result := Properties.Backward;
end;

function TsgDXFText.GetGeneration: Byte;
begin
  Result := 2 * Ord(Backward) + 4 * Ord(UpsideDown);
end;

function TsgDXFText.GetInsideMText: Boolean;
begin
  Result := itfInsideMText in FInternalFlags;
end;

function TsgDXFText.GetFFontName: string;
begin
  Result := Properties.FFontName;
end;

function TsgDXFText.GetFontName: string;
begin
  if (Style = nil) or InsideMText then
    Result := FFont.Name
  else
    Result := Style.GetPrimaryFontName;
end;

function TsgDXFText.GetIsSHXFont: Boolean;
begin
  Result := not WinFont;
end;

function TsgDXFText.GetSymbolFromMultibyte(const AConverter: TsgDXFConverter;
  const ALeft, ARight: Byte; const ANumber: Integer;
  const AUnicodeAlways: Boolean): WideChar;
begin
  if AUnicodeAlways or (not WinFont and AConverter.UseSHXFonts) then
    Result := WideChar((ALeft shl 8) or ARight)
  else { \M+ }
    Result := GetMultibyteSymbol(ALeft, ARight, ANumber);
end;

function TsgDXFText.GetSHXUnicodeText: WideString;
begin
  Result := FSHXUnicodeText;
end;

function TsgDXFText.GetUnicodeText: WideString;
begin
  Result := FUnicodeText;
end;

function TsgDXFText.GetUpsideDown: Boolean;
begin
  if Style <> nil then
    Result := Properties.UpsideDown or Style.UpsideDown
  else
    Result := Properties.UpsideDown
end;

function TsgDXFText.GetWinFont: Boolean;
begin
  Result := itfWinFont in FInternalFlags;
end;

function TsgDXFText.SHXMatrix: TFMatrix;
begin
  Result := FMatrix;
end;

function TsgDXFText.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlHeight].Name).ValueAsDouble := Height;
  ANode.AddAttribNV(cnstXMLNames[xmlRotation].Name).ValueAsDouble := Rotation;
  ANode.AddAttribNV(cnstXMLNames[xmlWidthFactor].Name).ValueData.ValueAsSingle
    := XScale;
  ANode.AddAttribNV(cnstXMLNames[xmlObliqueAngle].Name).ValueAsDouble :=
    ObliqueAngle;
  ANode.AddAttribNV(cnstXMLNames[xmlText].Name).ValueAsStr := Text;
  if IsXMLHelp(AMode) then
    ANode.AddAttribNV(cnstXMLNames[xmlStyleName].Name)
  else if Assigned(Style) then
    ANode.AddAttribNV(cnstXMLNames[xmlStyleName].Name).ValueAsStr := Style.Name;
end;

procedure TsgDXFText.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FFont);
  FreeAndNil(FMText);
  DisposeAndNil(FTextParse);
  FreeAndNil(FTextStyleItem);
  FreeAndNil(FPropertiesItem);
end;

function TsgDXFText.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlHeight:
      Height := ANode.ValueAsDouble;
    xmlRotation:
      Rotation := ANode.ValueAsDouble;
    xmlObliqueAngle:
      ObliqueAngle := ANode.ValueAsDouble;
    xmlText:
      Text := ANode.ValueAsStr;
    xmlStyleName:
      Style := Converter.StyleByName(ANode.Value);
    xmlWidthFactor:
      XScale := ANode.ValueData.ValueAsSingle;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFText.GetThickness: Double;
begin
  Result := FLineWeight;
end;

procedure TsgDXFText.SetLWeight(Value: Integer);
begin
  if FLineWeight = 0 then
    FLineWeight := Value / 100;
end;

function TsgDXFText.GetIsUnicodeText: Boolean;
begin
  Result := (FUnicodeText <> '');
end;

function TsgDXFText.GetEntType: TsgCADEntities;
begin
  Result := ceText;
end;

function TsgDXFText.GetExtrusion: TFPoint;
begin
  Result := FExtrusion;
end;

function TsgDXFText.GetLineWeight: Double;
begin
  Result := FLineWeight;
end;

function TsgDXFText.GetIsEmpty: Boolean;
begin
  Result := (Trim(Text) = '') and (Trim(UnicodeText) = '');
end;

function TsgDXFText.GetXScale: Single;
begin
  Result := Properties.WidthFactor;
end;

procedure TsgDXFText.SetXScale(const Value: Single);
begin
  Properties.WidthFactor := Value;
end;

function TsgDXFText.GetOblique: Single;
begin
  Result := Properties.ObliqueAngle;
end;

{ TsgDXFMText }

procedure TsgDXFMText.ClearReferences;
begin
  inherited ClearReferences;
  Style := nil;
end;

constructor TsgDXFMText.Create;
begin
  inherited Create;
  FAlign := 1;
  FPoint1 := cnstFPointIllegal;
  Block := TsgDXFBlock.Create;
  FLineSpacingFactor := 1;
  FLineSpacingStyle := 1; // at least (taller characters will override)
  FTextStyleItem := TsgTableItem.Create;
end;

procedure TsgDXFMText.AssignEntity(Source: TsgDXFEntity);
var
  vMText: TsgDXFMText absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFMText then
  begin
    FAlign := vMText.FAlign;
    Block.Clear;
    FHeight := vMText.Height;
    FPoint1 := vMText.FPoint1;
    FLineSpacingFactor := vMText.FLineSpacingFactor;
    FRectWidth := vMText.FRectWidth;
    Style := vMText.Style;
    FLineSpacingStyle := vMText.FLineSpacingStyle;
    FText := vMText.FText;
    FLineWeight := vMText.FLineWeight;
  end;
end;

function TsgDXFMText.EntName: string;
begin
  Result := inherited EntName + ' ' + FText;
end;

function TsgDXFMText.HasSecond: Boolean;
// is the second alignment point must be used
begin
  Result := (Point1.X <> cnstIllegal) and (Point1.Y <> cnstIllegal);
end;

procedure TsgDXFMText.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(Style) and (Style.ClassType = TsgLinkObject) then
    Style := TsgDXFStyle(TsgLinkObject(Style)
      .GetObject(AConverter.Sections[csStyles]));
end;

procedure TsgDXFMText.LoadedInternal(AConverter: TsgDXFConverter);
var
  X, Y, vAngle: Double;
  vPt, vExtrusion: TFPoint;
begin
  if Style = nil then
    Style := AConverter.StyleByName(sStandardName);
  Block.Clear;
  Block.IsLoaded := False;
  if Parsing(AConverter, nil, cnstColorCADByLayer, 0) then
  begin
    Block.IsLoaded := False;
    Block.Loaded(AConverter);
    X := Block.Box.Right - Block.Box.Left;
    Y := Block.Box.Top - Block.Box.Bottom;
    if X < RectWidth then
      X := RectWidth;
    Block.FOffset := cnstFPointZero;
    case Align of
      2, 5, 8:
        Block.FOffset.X := X / 2;
      3, 6, 9:
        Block.FOffset.X := X;
      10: { new }
        Block.FOffset.X := 0;
    end;
    case Align of
      4, 5, 6:
        Block.FOffset.Y := -Y / 2;
      7, 8, 9:
        Block.FOffset.Y := -Y;
      10: { new }
        Block.FOffset.Y := -Y / 2 - Height / 2;
    end;
    if Layer = nil then
      Layer := AConverter.LayerByName('0');
    if HasSecond and not CompareMem(@FPoint1, @FExtrusion, SizeOf(FPoint1)) then
    begin
      vPt := sgFunction.Vector(FExtrusion, FPoint1);
      vExtrusion := sgFunction.Vector(FPoint1, vPt);
      vPt := FPoint1;
      DoPreExtrusion(vPt, vExtrusion);
      vAngle := Degree(ArcTan2(vPt.Y, vPt.X));
    end
    else
    begin
      vAngle := Angle;
      vExtrusion := Extrusion;
    end;
    FBox := Block.FBox;
    FMatrix := FMatXMat(StdMat(cnstFPointSingle, Reverse(GetBlockOffset)),
      StdMat(Scale, cnstFPointZero));
    FMatrix := FMatXMat(FMatrix, MatFromExtr(vExtrusion, vAngle));
    // 0 -> vAngle
    FMatrix := FMatXMat(FMatrix, StdMat(cnstFPointSingle, Point));
    if not IsBadRect(FBox) then
      TransRectCorners(FBox, FMatrix);
  end
  else
    FBox := cnstBadRect;
end;

function TsgDXFMText.Parsing(const AConverter: TsgDXFConverter; AList: TList;
  const AColor: TsgColorCAD; ASize: Double): Boolean;
var
  vMTextParser: TsgMTextParser;
begin
  vMTextParser := TsgMTextParser.Create(AConverter);
  try
    vMTextParser.FCells := AList;
    vMTextParser.FCellColor := AColor;
    vMTextParser.FCellSize := ASize;
    Result := vMTextParser.Parse(Self, Self.Block);
  finally
    vMTextParser.Free;
  end;
end;

procedure TsgDXFMText.ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord);
begin
  // do nothing, MText must use only self created block
end;

procedure TsgDXFMText.SetLWeight(Value: Integer);
begin
  if FLineWeight = 0 then
    FLineWeight := Value / 100;
end;

procedure TsgDXFMText.SetRectWidth(const Value: Single);
begin
  FRectWidth := Value;
end;

function TsgDXFMText.GetThickness: Double;
begin
  Result := FLineWeight;
end;

function TsgDXFMText.GetHeight: TsgFloat;
begin
  Result := FHeight;
end;

function TsgDXFMText.GetRectWidth: Single;
begin
  Result := FRectWidth;
end;

procedure TsgDXFMText.SetHeight(AValue: TsgFloat);
begin
  FHeight := AValue;
end;

procedure TsgDXFMText.SetHyphenation(const AValue: Boolean);
begin
  FHyphenation := AValue;
end;

function TsgDXFMText.GetStyle: TsgDXFStyle;
begin
  Result := TsgDXFStyle(FTextStyleItem.Item);
end;

procedure TsgDXFMText.SetStyle(AValue: TsgDXFStyle);
begin
  FTextStyleItem.Item := AValue;
end;

function TsgDXFMText.GetText: string;
begin
  Result := FText;
end;

function TsgDXFMText.GetTextStyleInternal: Pointer;
begin
  Result := Style;
end;

procedure TsgDXFMText.SetTextValue(AValue: string);
begin
  FText := AValue;
end;

function TsgDXFMText.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlHeight].Name).ValueAsDouble := Height;
  if IsXMLHelp(AMode) then
    ANode.AddAttribNV(cnstXMLNames[xmlStyleName].Name)
  else if Assigned(Style) then
    ANode.AddAttribNV(cnstXMLNames[xmlStyleName].Name).ValueAsStr := Style.Name;
  ANode.AddAttribNV(cnstXMLNames[xmlRectWidth].Name).ValueAsDouble := RectWidth;
  ANode.AddAttribNV(cnstXMLNames[xmlTextValue].Name).ValueAsStr := Text;
end;

procedure TsgDXFMText.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FTextStyleItem);
end;

function TsgDXFMText.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlHeight:
      Height := ANode.ValueAsDouble;
    xmlRectWidth:
      RectWidth := ANode.ValueAsDouble;
    xmlTextValue:
      Text := ANode.ValueAsStr;
    xmlStyleName:
      Style := Converter.StyleByName(ANode.Value);
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFMText.GetEntType: TsgCADEntities;
begin
  Result := ceMText;
end;

procedure TsgDXFMText.SetAngle(const Value: Single);
begin
  inherited SetAngle(Value);
  FPoint1 := cnstFPointIllegal;
end;

function TsgDXFMText.GetAlign: Byte;
begin
  Result := FAlign;
end;

procedure TsgDXFMText.SetAlign(const Value: Byte);
begin
  FAlign := Value;
end;

function TsgDXFMText.GetLineSpacingStyle: Byte;
begin
  Result := FLineSpacingStyle;
end;

procedure TsgDXFMText.SetLineSpacingStyle(const Value: Byte);
begin
  FLineSpacingStyle := Value;
end;

function TsgDXFMText.GetLineSpacingFactor: Single;
begin
  Result := FLineSpacingFactor;
end;

procedure TsgDXFMText.SetLineSpacingFactor(const Value: Single);
begin
  FLineSpacingFactor := Value;
end;

{ TsgDXFAttdef }

procedure TsgDXFAttdef.AssignEntity(Source: TsgDXFEntity);
var
  vAttdef: TsgDXFAttdef absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFAttdef then
  begin
    FFlags := vAttdef.FFlags;
    FHasChanging := False;
    Tag := vAttdef.Tag;
    Value := vAttdef.Value;
    LockPosition := vAttdef.LockPosition;
  end;
end;

constructor TsgDXFAttdef.Create;
begin
  inherited Create;
  FTagItem := TsgNamedItem.Create(Self);
end;

function TsgDXFAttdef.EntName: string;
var
  P: Integer;
begin
  Result := inherited EntName;
  P := Pos(' ', Result);
  if P > 0 then
    Insert(Tag + ' = ', Result, P + 1);
end;

procedure TsgDXFAttdef.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
begin
  if Self.ClassType = TsgDXFAttdef then
  begin
    if (AConverter.Params.Insert <> nil) and
      ((Flags = 0) or NotAppear or (Flags and 4 <> 0)) then
      Exit;
    if FHasChanging then
    begin
      FHasChanging := False;
      Exit;
    end;
    if AConverter.Params.Insert <> nil then
      if FText <> FValue then // if current ATTDEF is inside INSERT
      begin
        FText := FValue;
        LoadedInternal(AConverter);
      end;
  end
  else if NotAppear then
    Exit;
  inherited Invoke(AConverter, Proc, FinishProc);
end;

function TsgDXFAttdef.GetConstant: Boolean;
begin
  Result := (FFlags and 2) <> 0;
end;

function TsgDXFAttdef.GetEntType: TsgCADEntities;
begin
  Result := ceAttdef;
end;

function TsgDXFAttdef.GetFlags: Integer;
begin
  Result := FFlags;
end;

function TsgDXFAttdef.GetNotAppear: Boolean;
begin
  Result := (FFlags and 1) <> 0;
end;

function TsgDXFAttdef.GetOwner: TsgDXFEntity;
begin
  Result := FTagItem.Owner;
end;

function TsgDXFAttdef.GetStrValue: string;
begin
  Result := FValue;
end;

function TsgDXFAttdef.GetTag: string;
begin
  Result := FTagItem.Name;
end;

function TsgDXFAttdef.GetValue: string;
begin
  Result := FValue;
end;

procedure TsgDXFAttdef.SetConstant(const Value: Boolean);
begin
  FFlags := (FFlags and 253) or (Byte(Value) shl 1);
end;

procedure TsgDXFAttdef.SetFlags(const Value: Integer);
begin
  FFlags := Value;
end;

procedure TsgDXFAttdef.SetNotAppear(const Value: Boolean);
begin
  FFlags := (FFlags and 254) or Integer(Value);
end;

procedure TsgDXFAttdef.SetOwner(const Value: TsgDXFEntity);
begin
  FTagItem.Owner := Value;
end;

function TsgDXFAttdef.SetStrValue(S: string): Boolean;
begin
  FValue := S;
  Result := True;
end;

procedure TsgDXFAttdef.SetTag(const ATag: string);
begin
  Text := ATag; // if ATTDEF is not inside INSERT
  FTagItem.Name := Text;
end;

procedure TsgDXFAttdef.SetValue(const AValue: string);
begin
  FValue := AValue;
end;

function TsgDXFAttdef.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  // used only if ATTDEF is not inside INSERT
  ANode.RemoveAttributeByName(cnstXMLNames[xmlText].Name);
  //
  ANode.AddAttribNV(cnstXMLNames[xmlAttribTag].Name).ValueAsStr := Tag;
  ANode.AddAttribNV(cnstXMLNames[xmlAttribValue].Name).ValueAsStr := FValue;
end;

procedure TsgDXFAttdef.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FTagItem);
end;

function TsgDXFAttdef.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  case AType.ID of
    xmlText:
      Result := cnstXML_OK; // nothing
  else
    Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  end;
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlAttribTag:
      Tag := ANode.ValueAsStr;
    xmlAttribValue:
      Value := ANode.ValueAsStr;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

{ TsgDXFAttrib }

function TsgDXFAttrib.GetEntType: TsgCADEntities;
begin
  Result := ceAttrib;
end;

function TsgDXFAttrib.SetStrValue(S: string): Boolean;
begin
  Result := True;
  SetValue(S);
end;

procedure TsgDXFAttrib.SetTag(const ATag: string);
begin
  FTagItem.Name := ATag;
end;

procedure TsgDXFAttrib.SetValue(const AValue: string);
begin
  Text := AValue;
  FValue := Text;
end;

function TsgDXFAttrib.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
end;

function TsgDXFAttrib.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
end;

{ TsgDXFViewport }

constructor TsgDXFViewport.Create;
begin
  inherited Create;
  FBox := BadRect; // by default there is not boundary (only rectangle)
  FFrozenLayers := TsgInt64List.Create;
  FOrdIndex := -1;
  FStatusField := 1;
  FThisID := 1;
  FClippingBoundaryHandle := cnstBadHandle;
  FVisibleBoundary := True;
  FViewDirection.Z := 1;
  FXDataAppName := 'CADSoftTools';
  FOwnerItem := TsgOwneredItem.Create(Self);
end;

function TsgDXFViewport.BeginExtData(const AData: TsgCADExtendedData): Boolean;
begin
  AData.AddString(String_1001, sACADXDataAppName);
  AData.AddString(String_1000, cnstMView);
  AData.AddString(String_1002, '{');
  Result := True;
end;

procedure TsgDXFViewport.EndExtData(const AData: TsgCADExtendedData);
begin
  AData.AddString(String_1002, '}');
end;

procedure TsgDXFViewport.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FFrozenLayers);
  FreeAndNil(FOwnerItem);
end;

function TsgDXFViewport.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlPSpaceCenter:
      FPSpaceCenter := ANode.ValueAsFPoint;
    xmlMSpaceCenter:
      FMSpaceCenter := ANode.ValueAsFPoint;
    xmlViewDirection:
      FViewDirection := ANode.ValueAsFPoint;
    xmlViewTarget:
      FViewTarget := ANode.ValueAsFPoint;
    xmlPSpaceWidth:
      FPSpaceWidth := ANode.ValueAsDouble;
    xmlPSpaceHeight:
      FPSpaceHeight := ANode.ValueAsDouble;
    xmlFrontClipPlane:
      FFrontClipPlane := ANode.ValueAsDouble;
    xmlBackClipPlane:
      FBackClipPlane := ANode.ValueAsDouble;
    xmlMSpaceHeight:
      FMSpaceHeight := ANode.ValueAsDouble;
    xmlViewTwistAngle:
      FViewTwistAngle := ANode.ValueAsDouble;
    xmlStatusField:
      FStatusField := ANode.ValueAsInt;
    xmlThisID:
      FThisID := ANode.ValueAsInt;
    xmlClippingBoundaryHandle:
      FClippingBoundaryHandle := ANode.ValueAsHandle;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFViewport.CalcMatrix: TFMatrix;
var
  vPosition, vScale: TFPoint;
  vNewViewTarget: TFPoint;
begin
  vScale.X := FPSpaceHeight;
  vScale.Y := FMSpaceHeight;
  if vScale.X = 0 then
    vScale.X := 1.0;
  if vScale.Y = 0 then
    vScale.Y := vScale.X;
  vScale.X := vScale.X / vScale.Y; // from Model to Paper space
  vScale.Y := vScale.X;
  vScale.Z := vScale.X;
  if not NotZeroPoint(FViewDirection) then
    FViewDirection := cnstZOrtAxis;
  Result := GetViewTwistMatrix(FViewDirection, FViewTwistAngle);
  vNewViewTarget := FPointXMat(FViewTarget, Result);
  vPosition.X := FPSpaceCenter.X - (vNewViewTarget.X + FMSpaceCenter.X)
    * vScale.X;
  vPosition.Y := FPSpaceCenter.Y - (vNewViewTarget.Y + FMSpaceCenter.Y)
    * vScale.Y;
  vPosition.Z := FPSpaceCenter.Z - vNewViewTarget.Z * vScale.Z;
  Result := FMatXMat(Result, StdMat(vScale, vPosition));
end;

function TsgDXFViewport.CanDraw: Boolean;
begin
  Result := True;
end;

procedure TsgDXFViewport.ClearReferences;
begin
  inherited ClearReferences;
  FFrozenLayers.Clear;
  FClippingBoundary := nil;
  FClippingBoundaryHandle := cnstBadHandle;
end;

function TsgDXFViewport.GetBox: TFRect;
begin
  Result := BadRect;
  if GetDrawModel or (FStatusField = 0) then
    Result := FBox;
end;

procedure TsgDXFViewport.AssignEntity(Source: TsgDXFEntity);
var
  vViewPort: TsgDXFViewport absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFViewport then
  begin
    FBackClipPlane := vViewPort.FBackClipPlane;
    FClippingBoundary := vViewPort.FClippingBoundary;
    FClippingBoundaryHandle := vViewPort.FClippingBoundaryHandle;
    FFlags := vViewPort.FFlags;
    FFrontClipPlane := vViewPort.FFrontClipPlane;
    FFrozenLayers.Assign(vViewPort.FFrozenLayers);
    FMatrix := vViewPort.FMatrix;
    FMSpaceCenter := vViewPort.FMSpaceCenter;
    FMSpaceHeight := vViewPort.FMSpaceHeight;
    FOrdIndex := vViewPort.FOrdIndex;
    // FPaperSpaceBlock := vViewport.FPaperSpaceBlock;
    FPSpaceCenter := vViewPort.FPSpaceCenter;
    FPSpaceHeight := vViewPort.FPSpaceHeight;
    FPSpaceWidth := vViewPort.FPSpaceWidth;
    FStatusField := vViewPort.FStatusField;
    FThisID := vViewPort.FThisID;
    FViewDirection := vViewPort.FViewDirection;
    FViewTarget := vViewPort.FViewTarget;
    FViewTwistAngle := vViewPort.FViewTwistAngle;
    FVisibleBoundary := vViewPort.FVisibleBoundary;
    FXDataAppName := vViewPort.FXDataAppName;
  end;
end;

function TsgDXFViewport.GetBoundariesAsPoints
  (AConverter: TsgDXFConverter): TList;
var
  vClipBoundary: TsgDXFEntity;
  vPoly: TsgCADBasePolyline;
  vEntity: TsgDXFEntity;
  vRegion: TsgDXFRegion;
  vPoints: TList;
  vRect: TFRect;
  I: Integer;
begin
  Result := TList.Create;
  vClipBoundary := GetClipBoundary(AConverter);
  if vClipBoundary <> nil then
  begin
    if vClipBoundary is TsgCADBasePolyline then
    begin
      vPoly := TsgCADBasePolyline(vClipBoundary);
      AddListPointsPolyline(Result, vPoly, True, False);
    end
    else
    begin
      if vClipBoundary is TsgDXFRegion then
      begin
        vRegion := TsgDXFRegion(vClipBoundary);
        I := 0;
        repeat
          while I < vRegion.Count do
          begin
            vEntity := vRegion.Entities[I];
            Inc(I);
            if vEntity.EntType <> ceEntity then
            begin
              if vEntity is TsgDXFLine then
              begin
                vPoints := TList.Create;
                Result.Add(vPoints);
                vPoints.Capacity := 2;
                AddFPointInList(vPoints, TsgDXFLine(vEntity).Point);
                AddFPointInList(vPoints, TsgDXFLine(vEntity).Point1);
              end
              else
              begin
                if vEntity is TsgCADBasePolyline then
                begin
                  vPoly := TsgCADBasePolyline(vEntity);
                  AddListPointsPolyline(Result, vPoly, False,
                    (vPoly.Flags and 8) <> 0);
                end;
              end;
            end
            else
              Break;
          end;
        until I >= vRegion.Count;
      end;
    end;
  end
  else
  begin
    vRect := Rect;
    vPoints := TList.Create;
    Result.Add(vPoints);
    vPoints.Capacity := 5;
    AddFPointInList(vPoints, vRect.TopLeft);
    AddFPointInList(vPoints, MakeFPoint(vRect.Right, vRect.Top));
    AddFPointInList(vPoints, vRect.BottomRight);
    AddFPointInList(vPoints, MakeFPoint(vRect.Left, vRect.Bottom));
    AddFPointInList(vPoints, vRect.TopLeft);
  end;
end;

function TsgDXFViewport.GetBoundary(AConverter: TsgDXFConverter): TsgDXFEntity;
var
  I: Integer;
begin
  Result := FClippingBoundary;
  if (FClippingBoundary <> nil) or (AConverter = nil) then
    Exit;
  if FClippingBoundaryHandle = cnstBadHandle then
    Exit;
  if Owner = nil then
  begin
    I := AConverter.Sections[csEntities].IndexOfHandle(FClippingBoundaryHandle);
    if I > -1 then
      Result := AConverter.Entities[I];
  end
  else
  begin
    I := Owner.IndexOfHandle(FClippingBoundaryHandle);
    if I > -1 then
    begin
      Result := Owner.Entities[I];
      FClippingBoundary := Result; // only one search
      FClippingBoundaryHandle := cnstBadHandle;
    end;
  end;
end;

function TsgDXFViewport.GetClipBoundary(AConverter: TsgDXFConverter)
  : TsgDXFEntity;
var
  vEntity: TsgDXFEntity;
begin
  Result := nil;
  vEntity := GetBoundary(AConverter);
  if vEntity <> nil then
  begin
    if vEntity is TsgCADBasePolyline then
    begin
      if TsgCADBasePolyline(vEntity).PointCount > 2 then
        Result := vEntity;
    end
    else
    begin
      if (vEntity is TsgDXFRegion) and (TsgDXFRegion(vEntity).Count > 0) then
        Result := vEntity;
    end;
  end;
end;

procedure TsgDXFViewport.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
var
  PrevParams: TsgCADIterate;
  vMat: TFMatrix;
  vSavedMat: TFMatrix;
  vConv: TsgDXFConverter;
  vConvsMatrix: PFMatrix;

  procedure DoFrozenByViewportForLayers(const AFrozen: Boolean);
  var
    vLayer: TsgDXFLayer;
    I: Integer;
  begin
    if Assigned(FFrozenLayers) and (FFrozenLayers.Count > 0) then
      for I := 0 to AConverter.Counts[csLayers] - 1 do
      begin
        vLayer := AConverter.Layers[I];
        if FFrozenLayers.IndexOf(vLayer.Handle) >= 0 then
          vLayer.IsFrozenByViewPort := AFrozen;
      end;
  end;

  procedure ApplyLayers; // Adding new frozen to model
  begin
    DoFrozenByViewportForLayers(True);
  end;

  procedure RestoreLayers; // Extract new added frozen from model
  begin
    DoFrozenByViewportForLayers(False);
  end;

begin
  if FActive then
    Exit;
  if GetDrawModel then
  begin
    inherited Invoke(AConverter, Proc, FinishProc);
    if Assigned(Converter) then
    begin
      New(vConvsMatrix);
      try
        vConv := Converter.GetMainConverter(vConvsMatrix);
        vSavedMat := Converter.GetTransform3d;
        vConv.SetTransform3d(FMatXMat(FMatrix, vConv.GetTransform3d));
      finally
        Dispose(vConvsMatrix);
      end;
    end
    else
      vConv := nil;
    AConverter.FViewPortCut := True;
    AConverter.FViewPortRect := FBox;
    vMat := AConverter.FParams^.Matrix;
    AConverter.FViewPortRect.TopLeft := FPointXMat(FBox.TopLeft, vMat);
    AConverter.FViewPortRect.BottomRight := FPointXMat(FBox.BottomRight, vMat);
    NormFRect(AConverter.FViewPortRect);
    ApplyLayers;
    try
      PrevParams := AConverter.FParams^;
      AConverter.FParams^.Matrix :=
        FMatXMat(FMatrix, AConverter.FParams^.Matrix);
      AConverter.FParams^.DrawMatrix :=
        FMatXMat(FMatrix, AConverter.FParams^.DrawMatrix);
      AConverter.FParams^.Additional :=
        Ord(IsRotatedFMat(AConverter.FParams^.Matrix));
      AConverter.FParams^.Insert := nil;
      AConverter.FParams^.ConvertMatrixCurrentIndertToWCS := cnstIdentityMat;
      AConverter.FParams^.XScale := 0.0;
      AConverter.FParams^.YScale := 0.0;
      AConverter.FParams^.LType := StdLines;
      FActive := True;
      AConverter.GetModelLayout.Iterate(AConverter, Proc, FinishProc);
      // this Iterate only for Model Space
      AConverter.FParams^ := PrevParams;
    finally
      FActive := False;
      AConverter.FViewPortRect := BadRect;
      AConverter.FViewPortCut := False;
      RestoreLayers;
      if Assigned(vConv) then
        vConv.SetTransform3d(vSavedMat);
    end;
    if Assigned(FinishProc) then
      FinishProc(Self);
  end
  else if FStatusField = 0 then // Only boundary
  begin
    inherited Invoke(AConverter, Proc, FinishProc);
    if Assigned(FinishProc) then
      FinishProc(Self);
  end;
end;

function TsgDXFViewport.IsDraw: Boolean;
begin
  Result := VisibleBoundary or (not TurnsOff);
end;

function TsgDXFViewport.IsOwnerModel: Boolean;
begin
  Result := Assigned(Owner) and TsgDXFBlock(Owner).IsModalSpaceBlock;
end;

procedure TsgDXFViewport.LoadedInternal(AConverter: TsgDXFConverter);
begin
  FBox.Left := FPSpaceCenter.X - 0.5 * FPSpaceWidth;
  FBox.Top := FPSpaceCenter.Y + 0.5 * FPSpaceHeight;
  FBox.Right := FPSpaceCenter.X + 0.5 * FPSpaceWidth;
  FBox.Bottom := FPSpaceCenter.Y - 0.5 * FPSpaceHeight;
  FBox.Z1 := 0;
  FBox.Z2 := 0;
  FRect := FBox;
  FMatrix := CalcMatrix;
  if IsOwnerModel then
  begin
    TurnsOff := True;
    VisibleBoundary := False;
    FBox := cnstBadRect;
  end;
  inherited LoadedInternal(AConverter);
end;

procedure TsgDXFViewport.Offset(const P: TFPoint);
begin
  FMSpaceCenter.X := FMSpaceCenter.X + P.X;
  FMSpaceCenter.Y := FMSpaceCenter.Y + P.Y;
end;

procedure TsgDXFViewport.SetBoundary(ABoundary: TsgDXFEntity);
begin
  FClippingBoundary := ABoundary;
  FFlags := FFlags or $10000; // Enables non-rectangular clipping
end;

function TsgDXFViewport.GetDrawModel: Boolean;
begin
  Result := not TurnsOff; // $20000 = Turns the viewport off
  if Owner <> nil then
    Result := Result and (FOrdIndex > 0)
  else
    Result := Result and (FStatusField > 0) and
      ((FThisID <> 1) or (FOrdIndex > 0));
end;

function TsgDXFViewport.GetEntType: TsgCADEntities;
begin
  Result := ceViewport;
end;

function TsgDXFViewport.GetExtData(const AData: TsgCADExtendedData): Boolean;
begin
  BeginExtData(AData);
  AData.AddInt16(Integer_1070, 16);
  AData.AddPoint(Float_1010, ViewTarget);
  AData.AddPoint(Float_1010, ViewDirection);
  AData.AddDouble(Float_1040, ViewTwistAngle);
  AData.AddDouble(Float_1040, MSpaceHeight);
  AData.AddDouble(Float_1040, MSpaceCenter.X);
  AData.AddDouble(Float_1040, MSpaceCenter.Y);
  AData.AddDouble(Float_1040, 50.0); // DXF code 42
  AData.AddDouble(Float_1040, FrontClipPlane);
  AData.AddDouble(Float_1040, BackClipPlane);
  EndExtData(AData);
  Result := AData.DataCount > 0;
end;

function TsgDXFViewport.GetPSpaceCenter: TFPoint;
begin
  Result := FPSpaceCenter;
end;

function TsgDXFViewport.GetPSpaceHeight: Double;
begin
  Result := FPSpaceHeight;
end;

procedure TsgDXFViewport.SetPSpaceCenter(const Value: TFPoint);
begin
  FPSpaceCenter := Value;
end;

procedure TsgDXFViewport.SetPSpaceHeight(const Value: Double);
begin
  FPSpaceHeight := Value;
end;

function TsgDXFViewport.GetPSpaceWidth: Double;
begin
  Result := FPSpaceWidth;
end;

function TsgDXFViewport.GetScale: Double;
begin
  Result := 0;
  if FMSpaceHeight <> 0 then
    Result := FPSpaceHeight / FMSpaceHeight;
end;

function TsgDXFViewport.GetTurnsOff: Boolean;
begin
  Result := ((FFlags and $20000) <> 0) or IsOwnerModel;
end;

procedure TsgDXFViewport.SetPSpaceWidth(const Value: Double);
begin
  FPSpaceWidth := Value;
end;

procedure TsgDXFViewport.SetScale(const Value: Double);
begin
  if Value > 0 then
    FMSpaceHeight := FPSpaceHeight / Value;
end;

procedure TsgDXFViewport.SetTurnsOff(const Value: Boolean);
var
  vValue: Boolean;
begin
  vValue := Value or IsOwnerModel;
  FFlags := (FFlags and $FFFDFFFF) or ($20000 * Cardinal(vValue));
  FStatusField := IfThen(vValue, 0, -1);
end;

function TsgDXFViewport.GetViewDirection: TFPoint;
begin
  Result := FViewDirection;
end;

procedure TsgDXFViewport.SetViewDirection(const Value: TFPoint);
begin
  FViewDirection := Value;
end;

function TsgDXFViewport.GetViewTarget: TFPoint;
begin
  Result := FViewTarget;
end;

procedure TsgDXFViewport.SetViewTarget(const Value: TFPoint);
begin
  FViewTarget := Value;
end;

function TsgDXFViewport.GetViewTwistAngle: Single;
begin
  Result := FViewTwistAngle;
end;

function TsgDXFViewport.GetVisibleBoundary: Boolean;
begin
  Result := FVisibleBoundary;
end;

procedure TsgDXFViewport.SetViewTwistAngle(const Value: Single);
begin
  FViewTwistAngle := Value;
end;

procedure TsgDXFViewport.SetVisibleBoundary(const Value: Boolean);
begin
  FVisibleBoundary := Value;
  if IsOwnerModel then
    FVisibleBoundary := False;
end;

function TsgDXFViewport.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
var
  I: Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlPSpaceCenter].Name).ValueAsFPoint :=
    FPSpaceCenter;
  ANode.AddAttribNV(cnstXMLNames[xmlMSpaceCenter].Name).ValueAsFPoint :=
    FMSpaceCenter;
  ANode.AddAttribNV(cnstXMLNames[xmlViewDirection].Name).ValueAsFPoint :=
    FViewDirection;
  ANode.AddAttribNV(cnstXMLNames[xmlViewTarget].Name).ValueAsFPoint :=
    FViewTarget;
  ANode.AddAttribNV(cnstXMLNames[xmlPSpaceWidth].Name).ValueAsDouble :=
    FPSpaceWidth;
  ANode.AddAttribNV(cnstXMLNames[xmlPSpaceHeight].Name).ValueAsDouble :=
    FPSpaceHeight;
  ANode.AddAttribNV(cnstXMLNames[xmlFrontClipPlane].Name).ValueAsDouble :=
    FFrontClipPlane;
  ANode.AddAttribNV(cnstXMLNames[xmlBackClipPlane].Name).ValueAsDouble :=
    FBackClipPlane;
  ANode.AddAttribNV(cnstXMLNames[xmlMSpaceHeight].Name).ValueAsDouble :=
    FMSpaceHeight;
  ANode.AddAttribNV(cnstXMLNames[xmlViewTwistAngle].Name).ValueAsDouble :=
    FViewTwistAngle;
  ANode.AddAttribNV(cnstXMLNames[xmlStatusField].Name).ValueAsInt :=
    FStatusField;
  ANode.AddAttribNV(cnstXMLNames[xmlThisID].Name).ValueAsInt := FThisID;
  ANode.AddAttribNV(cnstXMLNames[xmlClippingBoundaryHandle].Name).ValueAsHandle
    := FClippingBoundaryHandle;
  for I := 0 to FFrozenLayers.Count - 1 do
  begin
  end;
end;



// procedure TdxfViewport.Commit(const AReader: TdxfReader);
// var
// vViewport: TsgDXFViewport;
// begin
// inherited Commit(AReader);
// vViewport := TsgDXFViewport(FEnt);






// vViewport.Handle := FHandle;
// AReader.Conv.SetHandle(vViewport);
// end;
//
// procedure TdxfViewport.ReadProperty(const AReader: TdxfReader);
// var
// vViewport: TsgDXFViewport;
// begin
// vViewport := TsgDXFViewport(FEnt);
// inherited ReadProperty(AReader);
// case AReader.Code of
// Integer_90:  vViewport.Flags := AReader.IntValue;
// String_340:  vViewport.ClippingBoundaryHandle := AReader.HandleValue;
// String_341, String_331: vViewport.FrozenLayers.Add(AReader.HandleValue);
// // acR2000 - String_341; acR2004+ - String_331; acR12 - 1003 (see below)
// String_1001:
// begin
// vViewport.XDataAppName := AReader.UValue;
// FIsAcad := vViewport.XDataAppName = sACADXDataAppName;
// end;
// end;
// case AReader.Code of
// 1003: if FIsAcad then vViewport.FrozenLayers.Add(AReader.Conv.LayerByName(AReader.UValue).Handle);
// 1040: if FIsAcad then NextReal(AReader);
// 1010,1020,1030: if FIsAcad then Next3Reals(AReader);
// end;
// end;

function TsgDXFViewport.GetMSpaceCenter: TFPoint;
begin
  Result := FMSpaceCenter;
end;

function TsgDXFViewport.GetOwner: TsgDXFEntity;
begin
  Result := FOwnerItem.Owner;
end;

procedure TsgDXFViewport.SetMSpaceCenter(const Value: TFPoint);
begin
  FMSpaceCenter := Value;
end;

procedure TsgDXFViewport.SetOwner(const Value: TsgDXFEntity);
begin
  FOwnerItem.Owner := Value;
end;

function TsgDXFViewport.GetFlags: Integer;
begin
  Result := FFlags;
end;

function TsgDXFViewport.GetFrontClipPlane: Single;
begin
  Result := FFrontClipPlane;
end;

procedure TsgDXFViewport.SetFlags(const Value: Integer);
begin
  FFlags := Value;
end;

procedure TsgDXFViewport.SetFrontClipPlane(const Value: Single);
begin
  FFrontClipPlane := Value;
end;

function TsgDXFViewport.GetBackClipPlane: Single;
begin
  Result := FBackClipPlane;
end;

procedure TsgDXFViewport.SetBackClipPlane(const Value: Single);
begin
  FBackClipPlane := Value;
end;

{ TsgDXFVport }

procedure TsgDXFVport.AssignEntity(Source: TsgDXFEntity);

var
  vVPort: TsgDXFVport absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFVport then
  begin
    FCircleZoomPercent := vVPort.FCircleZoomPercent;
    FUCSOrigin := vVPort.FUCSOrigin;
    FUCSXDir := vVPort.FUCSXDir;
    FUCSYDir := vVPort.FUCSYDir;
    FUCSVP := vVPort.FUCSVP;
    FViewAspectRatio := vVPort.FViewAspectRatio;
    FViewCenterPoint := vVPort.FViewCenterPoint;
    FViewDirection := vVPort.FViewDirection;
    FViewTarget := vVPort.FViewTarget;
    FViewHeight := vVPort.FViewHeight;
    FViewTwistAngle := vVPort.FViewTwistAngle;
  end;
end;

constructor TsgDXFVport.Create;
begin
  inherited Create;
  FViewDirection.Z := 1;
  FCircleZoomPercent := cntViewPortCircleZoomPercent;
  FViewAspectRatio := 1;
  FUCSOrigin.Z := 1;
  FUCSXDir.X := 1;
  FUCSYDir.Y := 1;
end;

function TsgDXFVport.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlCircleZoomPercent:
      FCircleZoomPercent := ANode.ValueAsInt;
    xmlUCSOrigin:
      FUCSOrigin := ANode.ValueAsFPoint;
    xmlUCSXDir:
      FUCSXDir := ANode.ValueAsFPoint;
    xmlUCSYDir:
      FUCSYDir := ANode.ValueAsFPoint;
    xmlUCSVP:
      FUCSVP := ANode.ValueAsBool;
    xmlViewAspectRatio:
      FViewAspectRatio := ANode.ValueAsDouble;
    xmlViewCenterPoint:
      FViewCenterPoint := ANode.ValueAsFPoint;
    xmlViewDirection:
      FViewDirection := ANode.ValueAsFPoint;
    xmlViewTarget:
      FViewTarget := ANode.ValueAsFPoint;
    xmlViewHeight:
      FViewHeight := ANode.ValueAsDouble;
    xmlViewTwistAngle:
      FViewTwistAngle := ANode.ValueAsDouble;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFVport.GetViewDirection: TFPoint;
begin
  Result := FViewDirection;
end;

function TsgDXFVport.GetViewHeight: TsgFloat;
begin
  Result := FViewHeight;
end;

function TsgDXFVport.GetViewTwistAngle: Double;
begin
  Result := FViewTwistAngle;
end;

procedure TsgDXFVport.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
  AConverter.IsHaveActiveVPort := True;
end;

procedure TsgDXFVport.SetViewDirection(const Value: TFPoint);
begin
  FViewDirection := Value;
  if (Value.X = 0) and (Value.Y = 0) and (Value.Z = 0) then
    FViewDirection.Z := 1;
end;

procedure TsgDXFVport.SetViewHeight(const Value: TsgFloat);
begin
  FViewHeight := Value;
end;

procedure TsgDXFVport.SetViewTwistAngle(const Value: Double);
begin
  FViewTwistAngle := Value;
end;

function TsgDXFVport.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlCircleZoomPercent].Name).ValueAsInt :=
    FCircleZoomPercent;
  ANode.AddAttribNV(cnstXMLNames[xmlUCSOrigin].Name).ValueAsFPoint :=
    FUCSOrigin;
  ANode.AddAttribNV(cnstXMLNames[xmlUCSXDir].Name).ValueAsFPoint := FUCSXDir;
  ANode.AddAttribNV(cnstXMLNames[xmlUCSYDir].Name).ValueAsFPoint := FUCSYDir;
  ANode.AddAttribNV(cnstXMLNames[xmlUCSVP].Name).ValueAsBool := FUCSVP;
  ANode.AddAttribNV(cnstXMLNames[xmlViewAspectRatio].Name).ValueAsDouble :=
    FViewAspectRatio;
  ANode.AddAttribNV(cnstXMLNames[xmlViewCenterPoint].Name).ValueAsFPoint :=
    FViewCenterPoint;
  ANode.AddAttribNV(cnstXMLNames[xmlViewDirection].Name).ValueAsFPoint :=
    FViewDirection;
  ANode.AddAttribNV(cnstXMLNames[xmlViewTarget].Name).ValueAsFPoint :=
    FViewTarget;
  ANode.AddAttribNV(cnstXMLNames[xmlViewHeight].Name).ValueAsDouble :=
    FViewHeight;
  ANode.AddAttribNV(cnstXMLNames[xmlViewTwistAngle].Name).ValueAsDouble :=
    FViewTwistAngle;
end;

{ TsgCADPolyPolygon }

function TsgCADPolyPolygon.ApplyAngle(const AngleRel: Double): Boolean;
begin
  Result := False;
end;

function TsgCADPolyPolygon.ApplyScale(const AScaleRel: Double): Boolean;
begin
  Result := False;
end;

procedure TsgCADPolyPolygon.AssignEntity(Source: TsgDXFEntity);
var
  vPolygon: TsgCADPolyPolygon absolute Source;
  I: Integer;
  vSourcePoints: TF2DPointList;
begin
  inherited AssignEntity(Source);
  if not(Source is TsgCADPolyPolygon) then
    Exit;
  if FBoundaryPolylines.Count <> 0 then
    ClearList(FBoundaryPolylines);
  FBoundaryPolylines.Capacity := vPolygon.FBoundaryPolylines.Count;
  for I := 0 to vPolygon.FBoundaryPolylines.Count - 1 do
  begin
    vSourcePoints := vPolygon.FBoundaryPolylines.Items[I];
    if (vSourcePoints = nil) or (vSourcePoints.Count = 0) then
      Continue;
    FBoundaryPolylines.Add(TF2DPointList.Create(vSourcePoints));
  end;
end;

procedure TsgCADPolyPolygon.CalcFMatrix;
begin
end;

function TsgCADPolyPolygon.CanDraw: Boolean;
begin
  Result := True;
end;

procedure TsgCADPolyPolygon.ClearBoundaryData;
begin
end;

procedure TsgCADPolyPolygon.ClearReferences;
begin
  inherited ClearReferences;
  ClearList(FBoundaryPolylines);
end;

procedure TsgCADPolyPolygon.CloseBoundary;
var
  I: Integer;
  vPoints: TF2DPointList;
begin
  for I := 0 to FBoundaryPolylines.Count - 1 do
  begin
    vPoints := FBoundaryPolylines[I];
    if (vPoints = nil) or (vPoints.Count = 0) then
      Continue;
    if not IsEqualF2DPoints(vPoints.First, vPoints.Last) then
      vPoints.Add(vPoints.First);
  end;
end;

constructor TsgCADPolyPolygon.Create;
begin
  inherited Create;
  FBoundaryPolylines := TList.Create;
  FBox := BadRect;
end;

function TsgCADPolyPolygon.BoxTransformation(AConverter: TsgDXFConverter;
  const ABox: TFRect): TFRect;
begin
  Result := ABox;
end;

function TsgCADPolyPolygon.GetBox: TFRect;
begin
  Result := BoxTransformation(Converter, FBox);
end;

function TsgCADPolyPolygon.GetBoxPoints(Proc: TFPointProc;
  Full: Boolean): Boolean;
begin
  Result := inherited GetBoxPoints(Proc, Full);
end;

function TsgCADPolyPolygon.GetEntType: TsgCADEntities;
begin
  Result := cePolyPolygon;
end;

function TsgCADPolyPolygon.GetHatchName: string;
begin
  Result := sSOLID;
end;

function TsgCADPolyPolygon.GetSolidFill: Boolean;
begin
  Result := True;
end;

procedure TsgCADPolyPolygon.LoadedInternal(AConverter: TsgDXFConverter);
var
  vPoints: TF2DPointList;
  I, J: Integer;
begin
  CalcFMatrix;
  if Layer = nil then
    Layer := AConverter.LayerByName('0');
  inherited LoadedInternal(AConverter);
  MakeBorderPolylines(AConverter);
  CloseBoundary;
  FBox := BadRect;
  if (FBoundaryPolylines = nil) or (FBoundaryPolylines.Count = 0) then
    Exit;
  for I := 0 to FBoundaryPolylines.Count - 1 do
  begin
    if FBoundaryPolylines[I] = nil then
      Continue;
    vPoints := FBoundaryPolylines[I];
    for J := 0 to vPoints.Count - 1 do
      ExpandFRect(FBox, MakeFPoint(vPoints[J].X, vPoints[J].Y, 0));
  end;
  if FBox.Bottom = BadRect.Bottom then
    Exit;
  NormFRect(FBox);
  ParseLines;
end;

procedure TsgCADPolyPolygon.MakeBorderPolylines(AConverter: TsgDXFConverter);
begin
end;

procedure TsgCADPolyPolygon.ParseLines;
begin
end;

procedure TsgCADPolyPolygon.SetHatchName(const AHatchName: string);
begin
end;

procedure TsgCADPolyPolygon.SetSolidFill(const Value: Boolean);
begin
end;

function TsgCADPolyPolygon.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlHatchName].Name).ValueAsStr := HatchName;
  ANode.AddAttribNV(cnstXMLNames[xmlSolidFill].Name).ValueAsBool := SolidFill;
end;

procedure TsgCADPolyPolygon.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FBoundaryPolylines);
end;

function TsgCADPolyPolygon.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    // xmlHatchName: HatchName := ANode.ValueAsStr;
    xmlSolidFill:
      SolidFill := ANode.ValueAsBool;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

{ TsgCADWipeout }

constructor TsgCADWipeout.Create;
begin
  inherited Create;
  FClipPoints := TList.Create;
  FUVector := cnstXOrtAxis;
  FVVector := cnstYOrtAxis;
  FSize := cnstFPointSingle;
  FFlags := 7;
end;

function TsgCADWipeout.GetClipPointsCount: Integer;
begin
  Result := FClipPoints.Count;
end;

function TsgCADWipeout.GetClosed: Boolean;
begin
  Result := True;
end;

function TsgCADWipeout.GetClipPoint(Index: Integer): TF2DPoint;
begin
  Result := PF2DPoint(FClipPoints[Index])^;
end;

function TsgCADWipeout.GetEntType: TsgCADEntities;
begin
  Result := ceWipeout;
end;

function TsgCADWipeout.GetHeight: Double;
begin
  Result := Size.Y * Sqrt(Sqr(VVector.X) + Sqr(VVector.Y));
end;

function TsgCADWipeout.GetMatrix: TFMatrix;
  procedure InitV(var V: array of Double; const APt: TFPoint);
  begin
    V[0] := APt.X;
    V[1] := APt.Y;
    V[2] := APt.Z;
  end;

begin
  InitV(Result.V1, UVector);
  InitV(Result.V2, VVector);
  InitV(Result.V3, cnstZOrtAxis);
  InitV(Result.V4, Point);
end;

function TsgCADWipeout.GetPoint1: TFPoint;
begin
  Result := GetPointInternal(Size.X, 0);
end;

function TsgCADWipeout.GetPoint2: TFPoint;
begin
  Result := GetPointInternal(0, Size.Y);
end;

function TsgCADWipeout.GetPoint3: TFPoint;
begin
  Result := GetPointInternal(Size.X, Size.Y);
end;

function TsgCADWipeout.GetPointInternal(X, Y: Double): TFPoint;
begin
  Result.X := Point.X + X * UVector.X + Y * VVector.X;
  Result.Y := Point.Y + X * UVector.Y + Y * VVector.Y;
  Result.Z := Point.Z + X * UVector.Z + Y * VVector.Z;
end;

function TsgCADWipeout.GetWidth: Double;
begin
  Result := Size.X * Sqrt(Sqr(UVector.X) + Sqr(UVector.Y));
end;

procedure TsgCADWipeout.ChangeSizes(K: Double);
begin
  if K <> 0 then
  begin
    K := Abs(K);
    FUVector.X := K * FUVector.X;
    FUVector.Y := K * FUVector.Y;
    FVVector.X := K * FVVector.X;
    FVVector.Y := K * FVVector.Y;
  end;
end;

procedure TsgCADWipeout.ClearReferences;
begin
  inherited ClearReferences;
  ClearRecordList(FClipPoints);
end;

procedure TsgCADWipeout.SetClipPoint(Index: Integer; const P: TF2DPoint);
begin
  PF2DPoint(FClipPoints[Index])^ := P;
end;

procedure TsgCADWipeout.SetClosed(const AClosed: Boolean);
begin
end;

procedure TsgCADWipeout.SetHeight(const Value: Double);
begin
  ChangeSizes(Value / Height);
end;

procedure TsgCADWipeout.SetWidth(const Value: Double);
begin
  ChangeSizes(Value / Width);
end;

function TsgCADWipeout.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlUVector].Name).ValueAsFPoint := UVector;
  ANode.AddAttribNV(cnstXMLNames[xmlVVector].Name).ValueAsFPoint := VVector;
  ANode.AddAttribNV(cnstXMLNames[xmlSize].Name).ValueAsFPoint := Size;
  ANode.AddAttribNV(cnstXMLNames[xmlWidth].Name).ValueAsDouble := Width;
  ANode.AddAttribNV(cnstXMLNames[xmlHeight].Name).ValueAsDouble := Height;
end;

procedure TsgCADWipeout.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FClipPoints);
end;

function TsgCADWipeout.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlUVector:
      UVector := ANode.ValueAsFPoint;
    xmlVVector:
      VVector := ANode.ValueAsFPoint;
    xmlSize:
      Size := ANode.ValueAsFPoint;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure TsgCADWipeout.AddPoint(X, Y: Double);
var
  P2D: PF2DPoint;
begin
  New(P2D);
  P2D.X := X;
  P2D.Y := Y;
  FClipPoints.Add(P2D);
end;

procedure TsgCADWipeout.AssignEntity(Source: TsgDXFEntity);
var
  W: TsgCADWipeout absolute Source;
  I: Integer;
  P2D: PF2DPoint;
begin
  inherited AssignEntity(Source);
  if Source is TsgCADWipeout then
  begin
    FClippingBoundaryType := W.FClippingBoundaryType;
    FUseClipping := W.FUseClipping;
    FUVector := W.FUVector;
    FVVector := W.FVVector;
    FSize := W.FSize;
    ClearRecordList(FClipPoints);
    FClipPoints.Count := W.ClipPointsCount;
    for I := 0 to FClipPoints.Count - 1 do
    begin
      New(P2D);
      FClipPoints.List[I] := P2D;
      P2D^ := PF2DPoint(W.FClipPoints.List[I])^;
    end;
  end;
end;
{$IFNDEF EVG}

procedure TsgCADWipeout.CreateDottedList;
begin
  inherited CreateDottedList;
  if not Lines.IsSolid then
  begin
    if (FDottedSingPts = nil) or (FDottedSingPts = FPolyPoints) then
      FDottedSingPts := TList.Create
    else
      ClearRecordList(DottedSingPts);
    Lines.Poly(FPolyPoints, DottedSingPts, True);
  end;
end; {$ENDIF}

procedure TsgCADWipeout.ReloadPolyPoints;
var
  I: Integer;
begin
  inherited ReloadPolyPoints;
  Closed := True;
  if ClippingBoundaryType = 1 then
  begin
    if FClipPoints.Count >= 2 then
    begin
      FPolyPoints.Add(GetPointInternal(0.5 + ClipPoints[0].X,
        Size.Y - 0.5 - ClipPoints[0].Y));
      FPolyPoints.Add(GetPointInternal(0.5 + ClipPoints[1].X,
        Size.Y - 0.5 - ClipPoints[0].Y));
      FPolyPoints.Add(GetPointInternal(0.5 + ClipPoints[1].X,
        Size.Y - 0.5 - ClipPoints[1].Y));
      FPolyPoints.Add(GetPointInternal(0.5 + ClipPoints[0].X,
        Size.Y - 0.5 - ClipPoints[1].Y));
    end;
  end
  else
  begin
    for I := 0 to FClipPoints.Count - 1 do
      FPolyPoints.Add(GetPointInternal(0.5 + ClipPoints[I].X,
        Size.Y - 0.5 - ClipPoints[I].Y));
  end;
end;

{ TsgCADCurvePolygon }

function TsgCADCurvePolygon.AddBoundaryList(const AFlags: Byte = 0)
  : Tsg2DBoundaryList;
begin
  Result := FBoundaryData.AddBoundaryList(AFlags);
end;

procedure TsgCADCurvePolygon.AssignEntity(Source: TsgDXFEntity);
var
  vPolygon: TsgCADCurvePolygon absolute Source;
begin
  inherited AssignEntity(Source);
  if not(Source is TsgCADCurvePolygon) then
    Exit;
  CopyBoundaryData(TsgCADCurvePolygon(Source));
  FElevation := vPolygon.FElevation;
  FExtrusion := vPolygon.FExtrusion;
  FMatrix := vPolygon.FMatrix;
end;

procedure TsgCADCurvePolygon.CalcFMatrix;
begin
  if UseMatrix then
    FMatrix := FMatXMat(StdMat(cnstFPointSingle, FElevation),
      MatFromExtr(FExtrusion, 0.0))
  else
    FMatrix := cnstIdentityMat;
end;

procedure TsgCADCurvePolygon.ClearBoundaryData;
begin
  FBoundaryData.ClearBoundaries;
end;

procedure TsgCADCurvePolygon.ClearReferences;
begin
  inherited ClearReferences;
  ClearBoundaryData;
end;

procedure TsgCADCurvePolygon.CopyBoundaryData(const APolygon
  : TsgCADCurvePolygon);
begin
  FBoundaryData.ClearBoundaries;
  if Assigned(APolygon.FBoundaryData) then
    FBoundaryData.CopyBoundaries(APolygon.FBoundaryData);
end;

procedure TsgCADCurvePolygon.ChechBoundaryData(const AHatch
  : TsgCADCurvePolygon);
begin
  CheckListOfObject(FBoundaryData.Boundaries, AHatch.FBoundaryData.Boundaries,
    Tsg2DBoundaryList, True);
end;

constructor TsgCADCurvePolygon.Create;
begin
  inherited Create;
  FBoundaryData := TsgCADBoundaryData.Create;
  FExtrusion := cnstExtrusion;
  FMatrix := cnstIdentityMat;
end;

procedure TsgCADCurvePolygon.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FBoundaryData);
end;

function TsgCADCurvePolygon.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlBoundaries:
      begin
        FBoundaryData.Clear;
        FBoundaryData.FromXML(ANode, AResult);
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgCADCurvePolygon.BoxTransformation(AConverter: TsgDXFConverter;
  const ABox: TFRect): TFRect;
begin
  Result := ABox;
  if (Assigned(AConverter) and (AConverter.ImportMode <> imImport)) and
    UseMatrix and not IsBadRect(FBox) then
    TransRectCorners(Result, FMatrix);
end;

function TsgCADCurvePolygon.GenerateListOfBoundaries(const AList: TList;
  AExplodePolyline: Boolean = False): TFRect;
begin
  Result := FBoundaryData.GenerateListOfBoundaries(AList, AExplodePolyline);
end;

function TsgCADCurvePolygon.GetBoundaryData(const AIndex: Integer)
  : Tsg2DBoundaryList;
begin
  Result := FBoundaryData.Boundaries[AIndex];
end;

function TsgCADCurvePolygon.GetBoundaryDataCount: Integer;
begin
  if FBoundaryData <> nil then
    Result := FBoundaryData.Boundaries.Count
  else
    Result := -1;
end;

function TsgCADCurvePolygon.GetBoundaryDataLast: Tsg2DBoundaryList;
begin
  if FBoundaryData <> nil then
    Result := FBoundaryData.Boundaries.Last
  else
    Result := nil;
end;

function TsgCADCurvePolygon.GetBoxPoints(Proc: TFPointProc;
  Full: Boolean): Boolean;
begin
  Result := False;
  if IsBadRect(FBox) then
    Exit;
  Proc(FBox.TopLeft);
  Proc(FBox.BottomRight);
  if not Full then
    Exit;
  Proc(MakeFPoint(FBox.Left, FBox.Top, FBox.Z2));
  Proc(MakeFPoint(FBox.Left, FBox.Bottom, FBox.Z1));
  Proc(MakeFPoint(FBox.Left, FBox.Bottom, FBox.Z2));
  Proc(MakeFPoint(FBox.Right, FBox.Top, FBox.Z1));
  Proc(MakeFPoint(FBox.Right, FBox.Top, FBox.Z2));
  Proc(MakeFPoint(FBox.Right, FBox.Bottom, FBox.Z1));
end;

function TsgCADCurvePolygon.GetElevation: TFPoint;
begin
  Result := FElevation;
end;

function TsgCADCurvePolygon.GetEntType: TsgCADEntities;
begin
  Result := ceCurvePolygon;
end;

function TsgCADCurvePolygon.GetExtrusion: TFPoint;
begin
  Result := FExtrusion;
end;

function TsgCADCurvePolygon.GetFillColor: TsgColorCAD;
begin
  Result := ColorCAD;
end;

function TsgCADCurvePolygon.GetMatrix: TFMatrix;
begin
  Result := FMatrix;
end;

function TsgCADCurvePolygon.GetOffset: TFPoint;
begin
  Result := cnstFPointZero;
end;

function TsgCADCurvePolygon.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  ListNotify(AEntity, lnAdded);
  Result := AEntity = FBoundaryData;
end;

procedure TsgCADCurvePolygon.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
var
  PrevParams: TsgCADIterate;
begin
  if UseMatrix then
  begin
    PrevParams := AConverter.FParams^;
    AConverter.FParams^.Matrix := FMatXMat(FMatrix, AConverter.FParams^.Matrix);
    AConverter.FParams^.XScale := 0.0;
    AConverter.FParams^.YScale := 0.0;
    inherited Invoke(AConverter, Proc, FinishProc);
    AConverter.FParams^ := PrevParams;
  end
  else
    inherited Invoke(AConverter, Proc, FinishProc);
end;

function TsgCADCurvePolygon.IsInvoke(AConverter: TsgDXFConverter): Boolean;
begin
  Result := True;
  if (AConverter.ImportMode = imImport) and AConverter.FViewPortCut then
    Result := (IntersectRects(FBox, AConverter.FViewPortRect,
      AConverter.Params.Matrix) <> -1);
end;

procedure TsgCADCurvePolygon.ListNotify(Ptr: Pointer;
  Action: TListNotification);
begin
  inherited ListNotify(Ptr, Action);
  case Action of
    lnAdded:
      begin
        if TObject(Ptr).InheritsFrom(TsgCADBoundaryData) then
        begin
          FBoundaryData.Free;
          FBoundaryData := TsgCADBoundaryData(Ptr);
        end;
      end;
  end;
end;

procedure TsgCADCurvePolygon.MakeBorderPolylines(AConverter: TsgDXFConverter);
begin
  FBoundaryData.MakeBorderPolylines(AConverter, FBoundaryPolylines, SolidFill);
end;

procedure TsgCADCurvePolygon.SetElevation(const Value: TFPoint);
begin
  FElevation.X := 0;
  FElevation.Y := 0;
  FElevation.Z := Value.Z;
end;

procedure TsgCADCurvePolygon.SetExtrusion(const Value: TFPoint);
begin
  FExtrusion := Value;
end;

procedure TsgCADCurvePolygon.SetFillColor(const Value: TsgColorCAD);
begin

end;

procedure TsgCADCurvePolygon.SetOffset(const Value: TFPoint);
begin
end;

function TsgCADCurvePolygon.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
var
  vBoundaries: TsgNode;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlElevation].Name).ValueAsFPoint := Elevation;
  ANode.AddAttribNV(cnstXMLNames[xmlExtrusion].Name).ValueAsFPoint := Extrusion;
  ANode.AddAttribNV(cnstXMLNames[xmlOffset].Name).ValueAsFPoint := Offset;
  vBoundaries := ANode.AddChildNV(FBoundaryData.GetNodeName);
  FBoundaryData.ToXMLNode(vBoundaries, AMode);
end;

function TsgCADCurvePolygon.UseMatrix: Boolean;
begin
  Result := Extruded(FExtrusion) or NotZeroPoint(FElevation);
end;

{ TsgCADHatch }

procedure TsgCADHatch.ClearHatchPatternData;
begin
  FHatchPatternData.ClearPatterns;
end;

procedure TsgCADHatch.ClearReferences;
begin
  inherited ClearReferences;
  FHatchPatternData.ClearReferences;
  FParsedLines.Clear;
end;

procedure TsgCADHatch.CopyHatchPatternData(const AHatch: TsgCADHatch);
begin
  FHatchPatternData.CopyPatterns(AHatch.FHatchPatternData);
  FHatchStyles := AHatch.FHatchStyles;
end;

constructor TsgCADHatch.Create;
begin
  inherited Create;
  SetFillStyle(fsCAD);
  FParsedLines := TFPointList.Create;
  FHatchPatternData := TsgCADHatchPatternData.Create;
end;

procedure TsgCADHatch.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FHatchPatternData);
  FreeAndNil(FParsedLines);
end;

function TsgCADHatch.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlPatternAngle:
      PatternAngle := ANode.ValueAsDouble;
    xmlPatternScale:
      PatternScale := ANode.ValueAsDouble;
    xmlPatterns:
      begin
        FHatchPatternData.Clear;
        FHatchPatternData.FromXML(ANode, AResult);
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgCADHatch.AddPatternData(const ABasePoint: TFPoint;
  const Angle: Double; const ASign: Integer): PsgHatchPatternData;
begin
  Result := FHatchPatternData.AddPatternData(ABasePoint, Angle, ASign);
end;

function TsgCADHatch.ApplyAngle(const AngleRel: Double): Boolean;
begin
  Result := (Abs(AngleRel) > fAccuracy) and (FHatchPatternData <> nil);
  if Result then
    FHatchPatternData.ApplyAngle(AngleRel);
end;

procedure TsgCADHatch.ApplyFillStyle(const AFillStyle: TsgFillStyle;
  const ABasePoint: TFPoint);
begin
  if AFillStyle <> fsCAD then
  begin
    ClearHatchPatternData;
    case AFillStyle of
      fsHorizontal:
        AddPatternData(ABasePoint, 0, 1);
      fsVertical:
        AddPatternData(ABasePoint, 90, 1);
      fsBDiagonal:
        AddPatternData(ABasePoint, 45, -1);
      fsFDiagonal:
        AddPatternData(ABasePoint, -45, 1);
      fsCross:
        begin
          AddPatternData(ABasePoint, 0, 1);
          AddPatternData(ABasePoint, 90, 1);
        end;
      fsDiagCross:
        begin
          AddPatternData(ABasePoint, 45, -1);
          AddPatternData(ABasePoint, -45, 1);
        end;
    end;
  end;
end;

function TsgCADHatch.ApplyScale(const AScaleRel: Double): Boolean;
begin
  Result := (Abs(AScaleRel - 1) > fAccuracy) and (FHatchPatternData <> nil);
  if Result then
    FHatchPatternData.ApplyScale(AScaleRel);
end;

procedure TsgCADHatch.AssignEntity(Source: TsgDXFEntity);
var
  vHatch: TsgCADHatch absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgCADHatch then
  begin
    FParsedLines.Clear(False);
    ClearHatchPatternData;
    CopyHatchPatternData(vHatch);
  end;
end;

procedure TsgCADHatch.ParseLines;
begin
  FParsedLines.Clear(False);
  if FillStyle <> fsCAD then
    Exit; // draw fill gdi
  try
    HatchStyle := FHatchPatternData.ParseLines(FParsedLines, FBoundaryPolylines,
      FBox, HatchStyle);
  except
    on EsgLimitMemoryUsesException do
    begin
      FParsedLines.Clear(True);
    end;
    on EsgLimitTimeUsesException do
    begin
      FParsedLines.Clear(True);
    end;
  end;
end;

function TsgCADHatch.GetEntType: TsgCADEntities;
begin
  Result := ceHatch;
end;

function TsgCADHatch.GetFillStyle: TsgFillStyle;
begin
  Result := TsgFillStyle((FHatchStyles and $FFFFFF00) shr 8);
end;

function TsgCADHatch.GetLineWeight: Double;
begin
  Result := FLineWeight;
end;

function TsgCADHatch.GetPatternAngle: TsgFloat;
begin
  Result := FHatchPatternData.Angle;
end;

function TsgCADHatch.GetPatternScale: TsgFloat;
begin
  Result := FHatchPatternData.Scale;
end;

function TsgCADHatch.GetSolidFill: Boolean;
begin
  Result := False;
end;

function TsgCADHatch.GetThickness: Double;
begin
  Result := FLineWeight;
end;

function TsgCADHatch.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  inherited InsertEntity(AIndex, AEntity); // ListNotify(AEntity, lnAdded);
  Result := AEntity = FHatchPatternData;
end;

function TsgCADHatch.GetHatchName: string;
begin
  Result := FHatchPatternData.Name;
  if Length(Result) = 0 then
    inherited GetHatchName;
end;

function TsgCADHatch.GetHatchStyle: TsgHatchStyle;
begin
  Result := TsgHatchStyle(FHatchStyles and $FF);
end;

function TsgCADHatch.GetHatchPatternData: TList;
begin
  Result := FHatchPatternData.Patterns;
end;

procedure TsgCADHatch.ListNotify(Ptr: Pointer; Action: TListNotification);
begin
  inherited ListNotify(Ptr, Action);
  case Action of
    lnAdded:
      if TObject(Ptr).InheritsFrom(TsgCADHatchPatternData) then
      begin
        FHatchPatternData.Free;
        FHatchPatternData := TsgCADHatchPatternData(Ptr);
      end;
  end;
end;

procedure TsgCADHatch.SetFillStyle(const Value: TsgFillStyle);
begin
  FHatchStyles := (FHatchStyles and $FF) or (Word(Value) shl 8);
end;

procedure TsgCADHatch.SetFillStyleWithApplyStyle(const Value: TsgFillStyle);
begin
  if FillStyle <> Value then
  begin
    SetFillStyle(Value);
    ApplyFillStyle(Value, cnstFPointZero);
  end;
end;

procedure TsgCADHatch.SetHatchName(const AHatchName: string);
begin
  FHatchPatternData.Name := AHatchName;
end;

procedure TsgCADHatch.SetHatchStyle(const Value: TsgHatchStyle);
begin
  FHatchStyles := (FHatchStyles and $FFFFFF00) or Byte(Value);
end;

procedure TsgCADHatch.SetLineWeight(Value: Double);
begin
  FLineWeight := Value;
end;

procedure TsgCADHatch.SetPatternAngle(const AVal: TsgFloat);
begin
  FHatchPatternData.DoAngle(AVal);
  if FillStyle <> fsCAD then
    FillStyle := fsCAD;
end;

procedure TsgCADHatch.SetPatternScale(const AVal: TsgFloat);
begin
  if AVal < fAccuracy then
    Exit;
  if FillStyle <> fsCAD then
    FillStyle := fsCAD;
  FHatchPatternData.DoScale(AVal);
end;

function TsgCADHatch.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
var
  vPatterns: TsgNode;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlPatternAngle].Name).ValueAsDouble :=
    PatternAngle;
  ANode.AddAttribNV(cnstXMLNames[xmlPatternScale].Name).ValueAsDouble :=
    PatternScale;
  vPatterns := ANode.AddChildNV(FHatchPatternData.GetNodeName);
  FHatchPatternData.ToXMLNode(vPatterns);
end;

{ TsgCADMPolygon }

procedure TsgCADMPolygon.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgCADMPolygon then
  begin
    FOffset := TsgCADMPolygon(Source).FOffset;
    FFillColor := TsgCADMPolygon(Source).FFillColor;
  end;
end;

procedure TsgCADMPolygon.CalcFMatrix;
begin
  inherited CalcFMatrix;
  FMatrix := FMatXMat(FMatByTranslate(FOffset.X, FOffset.Y, 0), FMatrix);
end;

constructor TsgCADMPolygon.Create;
begin
  inherited Create;
  SolidFill := True;
  FillColor := ColorCAD;
end;

function TsgCADMPolygon.GetEntType: TsgCADEntities;
begin
  Result := ceMPolygon;
end;

function TsgCADMPolygon.GetOffset: TFPoint;
begin
  Result.X := FOffset.X;
  Result.Y := FOffset.Y;
  Result.Z := 0;
end;

function TsgCADMPolygon.GetSolidFill: Boolean;
begin
  Result := FFlag and 1 <> 0;
end;

function TsgCADMPolygon.GetFillColor: TsgColorCAD;
begin
  Result := FFillColor;
end;

procedure TsgCADMPolygon.SetOffset(const Value: TFPoint);
begin
  FOffset.X := Value.X;
  FOffset.Y := Value.Y;
end;

procedure TsgCADMPolygon.SetSolidFill(const Value: Boolean);
begin
  FFlag := (FFlag and 254) or Byte(Value);
end;

function TsgCADMPolygon.UseMatrix: Boolean;
begin
  Result := True;
end;

procedure TsgCADMPolygon.SetFillColor(const Value: TsgColorCAD);
begin
  FFillColor := Value;
end;

{ TsgDXFGradient }
(*
  constructor TsgDXFGradient.Create;
  begin
  inherited Create;
  FColors := TList.Create;
  FPositions := TList.Create;
  end;

  destructor TsgDXFGradient.Destroy;
  begin
  if FMatrix <> nil then
  Dispose(FMatrix);
  FColors.Free;
  FPositions.Free;
  inherited Destroy;
  end;

  procedure TsgDXFGradient.AssignEntity(Source: TsgDXFEntity);
  var
  vGradient: TsgDXFGradient absolute Source;
  begin
  inherited AssignEntity(Source);
  if Source is TsgDXFGradient then
  begin
  FPData1 := vGradient.FPData1;
  FPData2 := vGradient.FPData2;
  FRadius := vGradient.FRadius;
  FGFlags := vGradient.FGFlags;
  FColors.Count := vGradient.FColors.Count;
  CopyMemory(FColors.List, vGradient.FColors.List, vGradient.FColors.Count shl 2);
  FPositions.Count := vGradient.FPositions.Count;
  CopyMemory
  (FPositions.List, vGradient.FPositions.List, vGradient.FPositions.Count shl 2);
  if vGradient.HasMatrix then
  Transform := vGradient.Transform
  else
  begin
  if FMatrix <> nil then
  begin
  Dispose(FMatrix);
  FMatrix := nil;
  end;
  end;
  end;
  end;

  function TsgDXFGradient.GetAbsParam: Boolean;
  begin
  Result := FGFlags and 1 <> 0;
  end;

  function TsgDXFGradient.GetEntType: TsgCADEntities;
  begin
  Result := ceGradient;
  end;

  function TsgDXFGradient.GetHatchName: string;
  begin
  Result := 'GRADIENT';
  end;

  function TsgDXFGradient.GetPData1: TFPoint;
  begin
  Result.X := FPData1.X;
  Result.Y := FPData1.Y;
  Result.Z := 0;
  end;

  function TsgDXFGradient.GetPData2: TFPoint;
  begin
  Result.X := FPData2.X;
  Result.Y := FPData2.Y;
  Result.Z := 0;
  end;

  function TsgDXFGradient.GetRadius: Double;
  begin
  Result := FRadius;
  end;

  function TsgDXFGradient.GetTransform: TFMatrix;
  begin
  if FMatrix = nil then
  Result := cnstIdentityMat
  else
  Result := FMatrix^;
  end;

  function TsgDXFGradient.HasMatrix: Boolean;
  begin
  Result := FMatrix <> nil;
  end;

  function TsgDXFGradient.IsHorizontal: Boolean;
  begin
  Result := FPData1.Y = FPData2.Y;
  end;

  function TsgDXFGradient.IsSpheric: Boolean;
  begin
  Result := FRadius > 0;
  end;

  function TsgDXFGradient.IsVertical: Boolean;
  begin
  Result := FPData1.X = FPData2.X;
  end;

  procedure TsgDXFGradient.SetAbsParams(const Value: Boolean);
  begin
  FGFlags := (FGFlags and 254) or Byte(Value);
  end;

  procedure TsgDXFGradient.SetPData1(const Value: TFPoint);
  begin
  FPData1.X := Value.X;
  FPData1.Y := Value.Y;
  end;

  procedure TsgDXFGradient.SetPData2(const Value: TFPoint);
  begin
  FPData2.X := Value.X;
  FPData2.Y := Value.Y;
  end;

  procedure TsgDXFGradient.SetRadius(const Value: Double);
  begin
  FRadius := Value;
  end;

  procedure TsgDXFGradient.SetTransform(const Value: TFMatrix);
  begin
  if CompareMem(@Value, @cnstIdentityMat, Sizeof(Value)) then
  begin
  if FMatrix <> nil then
  begin
  Dispose(FMatrix);
  FMatrix := nil;
  end;
  end
  else
  begin
  if FMatrix = nil then
  New(FMatrix);
  FMatrix^ := Value;
  end;
  end;
*)

{ TsvgStyleFill }

constructor TsgCADStyleFill.Create;
begin
end;

destructor TsgCADStyleFill.Destroy;
begin
  if FTransform <> nil then
    Dispose(FTransform);
  inherited Destroy;
end;

procedure TsgCADStyleFill.Assign(const AObj: TObject);
var
  vSFill: TsgCADStyleFill absolute AObj;
begin
  if not(AObj is TsgCADStyleFill) then
    Exit;
  FFlags := vSFill.FFlags;
  FRef := vSFill.FRef;
  Transform := vSFill.Transform;
  CopyMemory(@FValues[0], @vSFill.FValues[0], SizeOf(FValues));
end;

procedure TsgCADStyleFill.CheckParams;
begin
end;

function TsgCADStyleFill.GetLocal: Boolean;
begin
  Result := FFlags and 1 <> 0;
end;

function TsgCADStyleFill.GetPoint1: TFPoint;
begin
  Result.X := FValues[0];
  Result.Y := FValues[1];
  Result.Z := 0;
end;

function TsgCADStyleFill.GetTransform: TFMatrix;
begin
  if FTransform = nil then
    Result := cnstIdentityMat
  else
    Result := FTransform^;
end;

function TsgCADStyleFill.GetUnits: TsgStyleFillUnits;
begin
  if FFlags and 2 = 0 then
    Result := sfUserSpaceOnUse
  else
    Result := sfObjectBoundingBox;
end;

function TsgCADStyleFill.GetV0: Double;
begin
  Result := FValues[0];
end;

function TsgCADStyleFill.GetV1: Double;
begin
  Result := FValues[1];
end;

function TsgCADStyleFill.GetV2: Double;
begin
  Result := FValues[2];
end;

function TsgCADStyleFill.GetV3: Double;
begin
  Result := FValues[3];
end;

function TsgCADStyleFill.GetV4: Double;
begin
  Result := FValues[4];
end;

procedure TsgCADStyleFill.SetTransform(const Value: TFMatrix);
begin
  if CompareMem(@Value, @cnstIdentityMat, SizeOf(Value)) then
  begin
    if FTransform <> nil then
    begin
      Dispose(FTransform);
      FTransform := nil;
    end;
  end
  else
  begin
    if FTransform = nil then
      New(FTransform);
    FTransform^ := Value;
  end;
end;

procedure TsgCADStyleFill.SetLocal(const Value: Boolean);
begin
  FFlags := (FFlags and 254) or Byte(Value)
end;

procedure TsgCADStyleFill.SetPoint1(const Value: TFPoint);
begin
  FValues[0] := Value.X;
  FValues[1] := Value.Y;
end;

procedure TsgCADStyleFill.SetRef(const Value: TsgCADStyleFill);
begin
  FRef := Value;
end;

procedure TsgCADStyleFill.SetUnits(const Value: TsgStyleFillUnits);
var
  vFlag: Byte;
begin
  if Value = sfUserSpaceOnUse then
    vFlag := 0
  else
    vFlag := 2;
  FFlags := (FFlags and 253) or vFlag;
end;

procedure TsgCADStyleFill.SetV0(const Value: Double);
begin
  FValues[0] := Value;
end;

procedure TsgCADStyleFill.SetV1(const Value: Double);
begin
  FValues[1] := Value;
end;

procedure TsgCADStyleFill.SetV2(const Value: Double);
begin
  FValues[2] := Value;
end;

procedure TsgCADStyleFill.SetV3(const Value: Double);
begin
  FValues[3] := Value;
end;

procedure TsgCADStyleFill.SetV4(const Value: Double);
begin
  FValues[4] := Value;
end;

{ TsvgStyleGradient }

destructor TsgCADStyleGradient.Destroy;
begin
  if FStops <> nil then
    FStops.Free;
  Inherited Destroy;
end;

procedure TsgCADStyleGradient.SetRef(const Value: TsgCADStyleFill);
begin
  if Value is TsgCADStyleGradient then
    FRef := Value
  else
    FRef := nil;
end;

function TsgCADStyleGradient.GetLinear: Boolean;
begin
  Result := (FFlags and 4) <> 0;
end;

function TsgCADStyleGradient.GetPoint2: TFPoint;
begin
  Result.X := FValues[2];
  Result.Y := FValues[3];
  Result.Z := 0;
end;

procedure TsgCADStyleGradient.GetPositionColors(const APos: TsgSingleList;
  const AColor: TsgIntegerList);
var
  vStops: TsgSingleList;
  I, J, K: Integer;
  vColor: Integer;
  vIsLinear: Boolean;
begin
  if HasStops then
  begin
    vStops := GetStopList;
    AColor.Count := vStops.Count div 2;
    APos.Count := AColor.Count;
    I := 0;
    J := 0;
    K := AColor.Count - 1;
    vIsLinear := Linear;
    while I < vStops.Count do
    begin
      vColor := PInteger(@vStops.List[I])^;
      if vIsLinear then
        AColor[J] := vColor
      else
        AColor[K - J] := vColor;
      APos[J] := vStops[I + 1] * 0.01;
      Inc(I, 2);
      Inc(J);
    end;
  end;
end;

function TsgCADStyleGradient.GetSpreadMethod: TsgStyleGradSpreadMethod;
begin
  case FFlags and 24 of
    0:
      Result := smPad;
    8:
      Result := smReflect;
    16:
      Result := smRepeat;
  else
    Result := smPad;
  end;
end;

function TsgCADStyleGradient.GetStopList: TsgSingleList;
begin
  if FStops <> nil then
    Result := FStops
  else if FRef is TsgCADStyleGradient then
    Result := TsgCADStyleGradient(FRef).GetStopList
  else
    Result := nil;
end;

function TsgCADStyleGradient.GetStopsCount: Integer;
var
  vStops: TsgSingleList;
begin
  vStops := GetStopList;
  if vStops <> nil then
    Result := vStops.Count shr 1
  else
    Result := 0;
end;

function TsgCADStyleGradient.HasStops: Boolean;
var
  vStops: TsgSingleList;
begin
  Result := False;
  vStops := GetStopList;
  if (vStops <> nil) and (vStops.Count > 1) then
    Result := True;
end;

procedure TsgCADStyleGradient.SetLinear(const Value: Boolean);
begin
  FFlags := (FFlags and 251) or (Byte(Value) shl 2);
end;

procedure TsgCADStyleGradient.SetPoint2(const Value: TFPoint);
begin
  FValues[2] := Value.X;
  FValues[3] := Value.Y;
end;

procedure TsgCADStyleGradient.SetSpreadMethod(const Value
  : TsgStyleGradSpreadMethod);
var
  vFlag: Byte;
begin
  case Value of
    smPad:
      vFlag := 0;
    smReflect:
      vFlag := 1;
    smRepeat:
      vFlag := 2;
  else
    vFlag := 0;
  end;
  FFlags := (FFlags and 231) or (Byte(vFlag) shl 3);
end;

procedure TsgCADStyleGradient.AddStops(const AColor: Integer;
  const AOffset: Double);
var
  vOffset: Single;
  vIndex: Integer;
begin
  if FStops = nil then
    FStops := TsgSingleList.Create;

  vIndex := FStops.Add(0);
  PInteger(@FStops.List[vIndex])^ := AColor;

  vOffset := AOffset;
  FStops.Add(vOffset);
end;

procedure TsgCADStyleGradient.Assign(const AObj: TObject);
begin
  inherited Assign(AObj);
  if AObj is TsgCADStyleGradient then
    FStops.Assign(TsgCADStyleGradient(AObj).FStops);
end;

procedure TsgCADStyleGradient.CheckParams;
const
  cnst100per: Single = 100; // $42C80000;//
var
  I, J: Integer;
  vTmp: Single;
  vOffset: Single;
begin
  if (FStops = nil) or (FStops.Count < 4) then
    Exit;
  I := 1;
  while I < FStops.Count - 2 do
  begin
    J := I + 2;
    while J < FStops.Count do
    begin
      if FStops.List^[I] > FStops.List^[J] then
      begin
        vTmp := FStops.List[I];
        FStops.List[I] := FStops.List[J];
        FStops.List[J] := vTmp;

        vTmp := FStops.List^[I - 1];
        FStops.List^[I - 1] := FStops.List^[J - 1];
        FStops.List^[J - 1] := vTmp;
      end;
      Inc(J, 2);
    end;
    Inc(I, 2);
  end;
  if FStops.List^[FStops.Count - 1] < 10 then // can be max = 1.8
  begin
    I := 1;
    while I < FStops.Count do
    begin
      vOffset := FStops.List^[I] * 100;
      if vOffset < 0 then
        vOffset := 0
      else if vOffset > 100 then
        vOffset := 100;
      FStops.List^[I] := vOffset;
      Inc(I, 2);
    end;
  end
  else
  begin
    I := 1;
    while I < FStops.Count do
    begin
      vOffset := FStops.List^[I];
      if vOffset < 0 then
        FStops.List^[I] := 0
      else if vOffset > 100 then
        FStops.List[I] := cnst100per; // Single(100)
      Inc(I, 2);
    end;
  end;
  if FStops.List[1] > 0 then
  begin
    FStops.Insert(0, FStops.List[0]);
    FStops.Insert(1, 0);
  end;
  if FStops.List[FStops.Count - 1] < 100 then
  begin
    FStops.Add(FStops.List[FStops.Count - 2]);
    FStops.Add(cnst100per);
  end;
end;

{ TsvgStylePattern }

constructor TsgCADStylePattern.Create;
begin
  inherited Create;
  FEntities := TList.Create;
  FBox := cnstBadRect;
end;

destructor TsgCADStylePattern.Destroy;
begin
  FreeList(FEntities);
  inherited Destroy;
end;

procedure TsgCADStylePattern.AddEntity(const AEntity: TsgDXFEntity);
begin
  FEntities.Add(AEntity);
end;

procedure TsgCADStylePattern.Assign(const AObj: TObject);
var
  vSPattern: TsgCADStylePattern absolute AObj;
  I: Integer;
  vEnt, vNew: TsgDXFEntity;
begin
  inherited Assign(AObj);
  if AObj is TsgCADStylePattern then
  begin
    ClearList(FEntities, False);
    // for future version
    for I := 0 to vSPattern.FEntities.Count - 1 do
    begin
      vEnt := vSPattern.FEntities[I];
      vNew := TsgDXFEntityClass(vEnt.ClassType).Create;
      FEntities.Add(vNew);
      vNew.AssignEntity(vEnt);
    end;
  end;
end;

procedure TsgCADStylePattern.CheckParams;
begin
end;

function TsgCADStylePattern.GetContainerSize: TFRect;
begin
  Result := FBox;
end;

function TsgCADStylePattern.GetContainerBox: TFRect;
begin
  if FViewBox = nil then
    Result := FBox
  else
  begin
    Result.Left := FViewBox^.X;
    Result.Bottom := FViewBox^.Y;
    Result.Right := FViewBox^.X + FViewBox^.Width;
    Result.Top := FViewBox^.Y + FViewBox^.Height;
    Result.Z1 := 0;
    Result.Z2 := 0;
  end;
end;

// function TsgCADStylePattern.GetContainerByHatch: TList;
// begin
// if FEntities <> nil then
// Result := FEntities
// else
// if FRef is TsgCADStylePattern then
// Result := TsgCADStylePattern(FRef).GetContainerByHatch
// else
// Result := nil;
// end;

function TsgCADStylePattern.GetContentUnits: TsgStyleFillUnits;
begin
  if FFlags and 32 = 0 then
    Result := sfUserSpaceOnUse
  else
    Result := sfObjectBoundingBox;
end;

function TsgCADStylePattern.GetCount: Integer;
begin
  Result := FEntities.Count;
end;

function TsgCADStylePattern.GetEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := FEntities.List[AIndex];
end;

function TsgCADStylePattern.GetSize: TFPoint;
begin
  Result.X := FValues[2];
  Result.Y := FValues[3];
  Result.Z := 0;
end;

function TsgCADStylePattern.GetViewBox: TsgViewBox;
begin
  if FViewBox <> nil then
    Result := FViewBox^
  else
    Result := cnstViewBoxZero;
end;

procedure TsgCADStylePattern.Iterate(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
var
  I: Integer;
begin
  for I := 0 to FEntities.Count - 1 do
    TsgDXFEntity(FEntities.List[I]).Invoke(AConverter, Proc, FinishProc);
end;

procedure TsgCADStylePattern.Loaded(const AConverter: TsgDXFConverter);
var
  I: Integer;
  vEntity: TsgDXFEntity;
begin
  FBox := cnstBadRect;
  for I := 0 to FEntities.Count - 1 do
  begin
    vEntity := FEntities.List[I];
    AConverter.Loads(vEntity);
    UnionFRect(FBox, vEntity.Box);
  end;
end;

procedure TsgCADStylePattern.SetContentUnits(const Value: TsgStyleFillUnits);
var
  vFlag: Byte;
begin
  if Value = sfUserSpaceOnUse then
    vFlag := 0
  else
    vFlag := 1;
  FFlags := (FFlags and 223) or (vFlag shl 5);
end;

procedure TsgCADStylePattern.SetRef(const Value: TsgCADStyleFill);
begin
  if Value is TsgCADStylePattern then
    FRef := Value
  else
    FRef := nil;
end;

procedure TsgCADStylePattern.SetSize(const Value: TFPoint);
begin
  FValues[2] := Value.X;
  FValues[3] := Value.Y;
end;

procedure TsgCADStylePattern.SetViewBox(const Value: TsgViewBox);
begin
  if (Value.Width > 0) and (Value.Height > 0) then
  begin
    if FViewBox <> nil then
    begin
      Dispose(FViewBox);
      FViewBox := nil;
    end;
  end
  else
  begin
    if FViewBox <> nil then
    begin
      Dispose(FViewBox);
      FViewBox := nil;
    end;
  end;
end;

{ TsgCADFill }

procedure TsgCADFill.AssignEntity(Source: TsgDXFEntity);
var
  vFill: TsgCADFill absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgCADFill then
  begin
    FCADFillFlags := vFill.FCADFillFlags;
    StyleFill := vFill.StyleFill;
    FreeAndNil(FImage);
  end;
end;

procedure TsgCADFill.ClearReferences;
begin
  inherited ClearReferences;
end;

procedure TsgCADFill.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FImage);
  if (FStyleFill <> nil) and FStyleFill.Local then
    FreeAndNil(FStyleFill);
end;

function TsgCADFill.ConvertToImageEnt(const AConverter: TsgDXFConverter)
  : TsgDXFImageEnt;
const
  cnstMaxMetafileSize = cnstMaxImgSize * 1000;
var
  vCADImage: TsgCADImage;
  vExportImage: {$IFNDEF SGFPC}TMetafile {$ELSE}TsgBitMap{$ENDIF};
  vWidth, vHeight: Integer;
  vBox: TFRect;
  vCADFillFlags: Byte;
begin
  Result := nil;
  vBox := Self.Box;
  SetMaxMetafileExtents(Abs(vBox.Right - vBox.Left),
    Abs(vBox.Top - vBox.Bottom), vWidth, vHeight, cnstMaxMetafileSize);
  if (vWidth > 0) and (vHeight > 0) then
  begin
    vCADFillFlags := FCADFillFlags;
    vCADImage := TsgCADImage.Create;
    try
      vCADImage.Converter.InitializeSectionsBegin;
      vCADImage.Converter.InitializeSectionsEnd;
      vCADImage.CurrentLayout := vCADImage.Layouts[0];
      vCADImage.Transparent := True;
      vCADImage.BorderType := btGlobal;
      vCADImage.BorderSize := 0;
      vCADImage.IsWithoutBorder := True;
      vCADImage.CurrentLayout.AddEntity(Self);
      vCADImage.GetExtents;
      UseBuffer := False;
      vExportImage :=
      {$IFNDEF SGFPC}vCADImage.ExportToMetafile(vWidth, vHeight){$ELSE}nil{$ENDIF};
      try
        if vExportImage <> nil then
        begin
          Result := TsgDXFImageEnt.Create;
          try
            Result.SetImage(vExportImage);
            Result.Size := MakeFPoint(vExportImage.Width, vExportImage.Height);
            Result.Point := MakeFPoint(vBox.Left, vBox.Bottom, 0);
            Result.Loaded(AConverter);
            Result.UVector := MakeFPoint(Abs(vBox.Right - vBox.Left) /
              Abs(Result.Box.Left - Result.Box.Right), 0);
            Result.VVector := MakeFPoint(0, Abs(vBox.Top - vBox.Bottom) /
              Abs(Result.Box.Top - Result.Box.Bottom));
            Result.Loaded(AConverter);
          except
            FreeAndNil(Result);
          end;
        end;
      finally
        vExportImage.Free;
      end;
    finally
      FCADFillFlags := vCADFillFlags;
      vCADImage.CurrentLayout.RemoveEntity(Self);
      vCADImage.Free;
    end;
  end;
end;

function TsgCADFill.CreateBMPFill(const AMatrix: TFMatrix;
  const AClass: TClass): Boolean;
var
  vBMP: TBitmap;
  vPattern: TsgCADStylePattern;
  vHeight, vWidth, vPW, vPH, CX, CY, X, Y, PX, PY: Integer;
  vSDC, vDDC: THandle;
  vImgBox, vPatBox: TRect;
  vPatPos: TPoint;

  procedure SetRectWH(const ARect: TRect; var W, H: Integer);
  begin
    W := ARect.Right - ARect.Left;
    H := ARect.Bottom - ARect.Top;
  end;

  function GetScreenRect(ARect: TFRect): TRect;
  begin
    TransRectCorners(ARect, AMatrix);
    Result.Left := Floor(ARect.Left);
    Result.Top := Floor(ARect.Bottom);
    Result.Right := Ceil(ARect.Right);
    Result.Bottom := Ceil(ARect.Top);
    if Result.Left = Result.Right then
      Inc(Result.Right);
    if Result.Top = Result.Bottom then
      Inc(Result.Bottom);
  end;

  function GetPatSize: TRect;
  var
    vKX, vKY: Double;
  begin
    if vPattern.Units = sfUserSpaceOnUse then
      Result := GetScreenRect(MakeFRect(0, vPattern.Height, 0,
        vPattern.Width, 0, 0))
    else
    begin
      vKX := (vImgBox.Right - vImgBox.Left) / 100;
      vKY := (vImgBox.Bottom - vImgBox.Top) / 100;
      Result.Left := vImgBox.Left;
      Result.Top := vImgBox.Top;
      Result.Right := Result.Left + Ceil(vKX * vPattern.Width);
      Result.Bottom := Result.Top + Ceil(vKY * vPattern.Height);
    end;
    if Result.Left = Result.Right then
      Inc(Result.Right);
    if Result.Top = Result.Bottom then
      Inc(Result.Bottom);
  end;

  function GetPatPos: TPoint;
  var
    vKX, vKY: Double;
    vP: TFPoint;
  begin
    if vPattern.Units = sfUserSpaceOnUse then
    begin
      vP := FPointXMat(MakeFPoint(vPattern.X1, vPattern.Y1, 0), AMatrix);
      Result.X := Round(vP.X);
      Result.Y := Round(vP.Y);
    end
    else
    begin
      vKX := (vImgBox.Right - vImgBox.Left) / 100;
      vKY := (vImgBox.Bottom - vImgBox.Top) / 100;
      Result.X := vImgBox.Left + Ceil(vKX * vPattern.X1);
      Result.Y := vImgBox.Top + Ceil(vKY * vPattern.Y1);
    end;
  end;

  function GetStart(const vImg, VPat, vSize: Integer): Integer;
  var
    vDelta, vShift: Integer;
  begin
    vDelta := vImg - VPat;
    if vDelta = 0 then
      Result := 0
    else
    begin
      vShift := (vDelta div vSize) * vSize;
      Result := VPat + vShift - vImg;
    end;
  end;

begin
  Result := False;
  vPattern := TsgCADStylePattern(FStyleFill);
  vImgBox := GetScreenRect(FBox);
  SetRectWH(vImgBox, vWidth, vHeight);
  if (vWidth < cnstMaxImgSize) and (vHeight < cnstMaxImgSize) then
  begin
    vPatBox := GetPatSize;
    SetRectWH(vPatBox, vPW, vPH);
    if (vPW < cnstMaxImgSize) and (vPH < cnstMaxImgSize) then
    begin
      if FImage = nil then
      begin
        FImage := TBitmap.Create;
        FImage.PixelFormat := pf24bit;
      end
      else if (FImage.Width = vWidth) and (FImage.Height = vHeight) then
      begin
        Result := True;
        Exit; // FBitmap not changed
      end;
      SetSizeBmp(FImage, vWidth, vHeight);
      SetBackgroundColor(FImage);
      SetTransparentColor(FImage);

      vPatPos := GetPatPos;
      PX := GetStart(vImgBox.Left, vPatPos.X, vPW);
      PY := GetStart(vImgBox.Bottom, vPatPos.Y, vPH);

      vBMP := GetBush(vPW, vPH, AClass);
      try
        vSDC := vBMP.Canvas.Handle;
        vDDC := FImage.Canvas.Handle;
        CX := (vWidth + Abs(PX)) div vPW + 1;
        CY := (vHeight + Abs(PY)) div vPH + 1;
        for Y := 0 to CY do
          for X := 0 to CX do
            BitBlt(vDDC, PX + X * vPW, PY + Y * vPH, vPW, vPH, vSDC, 0,
              0, SRCCOPY);
        Result := True;
      finally
        vBMP.Free;
      end;
    end
    else
      FreeAndNil(FImage);
  end
  else
    FreeAndNil(FImage);
end;

function TsgCADFill.CreateBMPPattern(AWidth, AHeight: Integer;
  const AClass: TClass): TBitmap;
begin
  if AWidth > cnstMaxImgSize then
    AWidth := cnstMaxImgSize;
  if AHeight > cnstMaxImgSize then
    AHeight := cnstMaxImgSize;
  Result := GetBush(AWidth, AHeight, AClass);
  SetTransparentColor(Result);
end;

function TsgCADFill.GetBackground: TColor;
begin
  Result := clWhite;
end;

function TsgCADFill.GetBush(const W, H: Integer; AClass: TClass): TBitmap;
var
  I: Integer;
  vImg: TsgCADImage;
  vPattern: TsgCADStylePattern;
  vRect: TRect;
begin
  vRect := Rect(0, 0, W, H);
  vPattern := TsgCADStylePattern(FStyleFill);
  Result := TBitmap.Create;
  Result.PixelFormat := pf24bit;
  SetSizeBmp(Result, W, H);
  SetBackgroundColor(Result);
  if AClass = nil then
    AClass := TsgCADImage;
  vImg := TsgCADImageClass(AClass).Create;
  try
    vImg.Converter.InitializeSectionsBegin;
    vImg.Converter.InitializeSectionsEnd;
    vImg.Converter.DoExtents;
    vImg.CurrentLayout := vImg.Layouts[0];
    for I := 0 to vPattern.Count - 1 do
      vImg.CurrentLayout.PaperSpaceBlock.AddEntity(vPattern.Entities[I]);
    vImg.CurrentLayout.FBox := vPattern.ContainerBox;
    vImg.CurrentLayout.PaperSpaceBlock.FBox := vImg.CurrentLayout.FBox;
    vImg.CurrentLayout.PaperSpaceBlock.IsLoaded := True;
    vImg.Transparent := True;
    vImg.BorderSize := 0;
    vImg.BackgroundColor := Background;
    // vImg.GetExtents;
    vImg.CurrentLayout := vImg.Layouts[0];
    vImg.Stretch := True;
    vImg.GetExtents;
    vImg.Extents := vImg.CurrentLayout.FBox;
    Result.Canvas.StretchDraw(vRect, vImg);
  finally
    while vImg.CurrentLayout.PaperSpaceBlock.Count > 0 do
      vImg.CurrentLayout.PaperSpaceBlock.DeleteEntity(0);
    vImg.Free;
  end;
end;

function TsgCADFill.GetStyleFill: TsgCADStyleFill;
begin
  Result := FStyleFill;
end;

function TsgCADFill.GetUseBuffer: Boolean;
begin
  Result := FCADFillFlags and 1 = 0;
end;

function TsgCADFill.GroupExists: Boolean;
begin
  Result := True;
end;

function TsgCADFill.GroupFill(AConverter: TsgDXFConverter): Boolean;
var
  vImageEnt: TsgDXFImageEnt;
begin
  Result := False;
  vImageEnt := ConvertToImageEnt(AConverter);
  if Assigned(vImageEnt) then
  begin
    // Loaded(vImageEnt);
    Group.AddEntity(vImageEnt);
    Result := True;
  end;
end;

function TsgCADFill.GroupHasAddedEntities: Boolean;
begin
  Result := True;
end;

procedure TsgCADFill.LoadedInternal(AConverter: TsgDXFConverter);
begin
  if FStyleFill <> nil then
    FType := gtOther
  else
    FType := gtNone;
  inherited LoadedInternal(AConverter);
end;

procedure TsgCADFill.SetBackgroundColor(const ABmp: TBitmap);
begin
  ABmp.Canvas.Pen.Color := Background;
  ABmp.Canvas.Brush.Style := bsSolid;
  ABmp.Canvas.Brush.Color := Background;
  ABmp.Canvas.FillRect(ABmp.Canvas.ClipRect);
end;

procedure TsgCADFill.SetStyleFill(const Value: TsgCADStyleFill);
begin
  if (FStyleFill <> nil) and FStyleFill.Local then
  begin
    FStyleFill.Free;
    FStyleFill := nil;
  end;
  if (Value <> nil) and Value.Local then
  begin
    FStyleFill := TsgClassOfCADStyleFill(Value.ClassType).Create;
    FStyleFill.Assign(Value);
  end
  else
    FStyleFill := Value;
end;

procedure TsgCADFill.SetTransparentColor(const ABmp: TBitmap);
begin
  ABmp.Transparent := True;
  ABmp.TransparentColor := Background;
  ABmp.TransparentMode := tmFixed;
end;

procedure TsgCADFill.SetUseBuffer(const Value: Boolean);
begin
  FCADFillFlags := (FCADFillFlags and 254) or Byte(not Value);
end;

{ TsgDXFXRef }

function TsgDXFXref.CanDraw: Boolean;
begin
  Result := True;
end;

procedure TsgDXFXref.ClearReferences;
begin
  inherited ClearReferences;
  GlobalLoadingXRefsStack.Remove(Self);
end;

constructor TsgDXFXref.Create;
begin
  inherited Create;
  FInvokeConverters := TsgList.Create;
end;

procedure TsgDXFXref.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FCADImage);
  FreeAndNil(FInvokeConverters);
end;

function TsgDXFXref.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  vFileName: string;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlFileName:
      begin
        vFileName := ANode.ValueAsStr;
        if not SameText(vFileName, FPath) then
        begin
          AddCADImage(Converter, vFileName);
        end;
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFXref.GetBlock: TsgDXFBlock;
begin
  if GetOwner is TsgDXFBlock then
    Result := TsgDXFBlock(GetOwner)
  else
    Result := nil;
end;

function TsgDXFXref.GetBox: TFRect;
begin
  Result := FBox;
end;

function TsgDXFXref.GetEntType: TsgCADEntities;
begin
  Result := ceXRef;
end;

function TsgDXFXref.GetLayer: TsgDXFLayer;
begin
  Result := nil;
  if Assigned(GetOwner()) then
    Result := GetOwner().Layer;
end;

// procedure TsgDXFXRef.GraphicChange(Sender: TObject);
// begin
// end;

procedure TsgDXFXref.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
var
  PrevParams: TsgCADIterate;
  PrevViewPortCut, PrevAutoInsert: Boolean;
  PrevViewPortRect: TFRect;
  vConv: TsgDXFConverter;
  vSHXFontList: TsgSHXFontList;
begin
  if FCADImage <> nil then
  begin
    inherited Invoke(AConverter, Proc, FinishProc);
    try
      vConv := TsgCADImage(FCADImage).Converter;
      if FInvokeConverters.IndexOf(vConv) < 0 then
      begin
        FInvokeConverters.Add(vConv);
        try
          PrevParams := AConverter.FParams^;
          PrevViewPortRect := vConv.FViewPortRect;
          PrevViewPortCut := vConv.FViewPortCut;
          PrevAutoInsert := vConv.AutoInsert;
          vSHXFontList := AConverter.FSHXFonts;
          try
            vConv.FViewPortRect := AConverter.FViewPortRect;
            vConv.FViewPortCut := AConverter.FViewPortCut;
            vConv.AutoInsert := AConverter.AutoInsert;
            // vConv.Iterate(Proc, AConverter.FParams^);
            // Not setting AConverter.Params^.Insert
            AConverter.Params^.Color := clByLayer;
            AConverter.Params^.XScale := 0.0;
            AConverter.Params^.YScale := 0.0;
            AConverter.FSHXFonts := vConv.FSHXFonts;
            vConv.GetModelLayout.PaperSpaceBlock.Iterate(AConverter, Proc,
              FinishProc);
          finally
            AConverter.FSHXFonts := vSHXFontList;
            AConverter.FParams^ := PrevParams;
            vConv.FViewPortRect := PrevViewPortRect;
            vConv.FViewPortCut := PrevViewPortCut;
            vConv.AutoInsert := PrevAutoInsert;
          end;
        finally
          FInvokeConverters.Remove(vConv);
        end;
      end;
      // else circular reference
    finally
      if Assigned(FinishProc) then
        FinishProc(Self);
    end;
  end;
end;

procedure TsgDXFXref.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
  FBox := BadRect;
  if FCADImage <> nil then
  begin
    TsgCADImage(FCADImage).Converter.FOwnerConverter := AConverter;
    if TsgCADImage(FCADImage).Converter.GetModelLayout <> nil then
      FBox := TsgCADImage(FCADImage).Converter.GetModelLayout.Box;
    // always only Model Box
    TsgCADImage(FCADImage).Converter.NumberOfPartsInSpline :=
      AConverter.NumberOfPartsInSpline;
    TsgCADImage(FCADImage).Converter.NumberOfPartsInCircle :=
      AConverter.NumberOfPartsInCircle;
  end;
end;

function TsgDXFXref.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlFileName].Name).ValueAsStr := FPath;
end;

// procedure TsgDXFXRef.ProgressEvent(Sender: TObject; Stage: TProgressStage;
// PercentDone: Byte; RedrawNow: Boolean; const R: TRect; const Msg: string);
// begin
// if Assigned(FOwnerProgress) then
// FOwnerProgress(Sender, Stage, PercentDone, RedrawNow, R, Msg);
// end;

function TsgDXFXref.AddCADImage(const AMainConv: TsgDXFConverter;
  const AFilePath: string; ASearchPaths: TStrings = nil): Boolean;
var
  vPrevCADPreview: Boolean;
  vFileName: string;
  I: Integer;

  procedure FreeCADImage;
  begin
    // FOwnerProgress := nil;
    FreeAndNil(FCADImage);
  end;

{ Function FileExistsEx

  var AFileName: string - in/out parameter.

  If no AFileName extension, try find first with
  cnstSupportedSGXRefExtesions items as extension

  TODO: FileExists(): - change in the future version the xref with network path
}
  function FileExistsEx(var AFileName: string): Boolean;
  const
    // ??extensions priority: 'dwg', 'dxf', ...
    cnstSupportedSGXRefExtesions: array [0 .. 1] of string = ('.dxf', '.dwg');
  var
    J: Integer;
  begin
    Result := False;
    if ExtractFileExt(AFileName) = '' then
    begin
      J := High(cnstSupportedSGXRefExtesions);
      while not Result and (J >= Low(cnstSupportedSGXRefExtesions)) do
        if (XRefFileClasses.IndexOf(cnstSupportedSGXRefExtesions[J]) >= 0) and
          FileExists(AFileName + cnstSupportedSGXRefExtesions[J]) then
          Inc(Result)
        else
          Dec(J);
      if Result then
        AFileName := AFileName + cnstSupportedSGXRefExtesions[J];
    end
    else
      Result := FileExists(AFileName);
  end;

  function ForcePathSlash(const APath: string): string;
  begin
    Result := APath;
    if (Result <> '') and (Result[Length(Result)] <> PathDelim) then
      Result := Result + PathDelim;
  end;

begin
  FreeCADImage;
  FPath := AFilePath;
  Result := FileExistsEx(FPath);
  if not Result then
  begin
    FPath := ExtractFileName(FPath);
    Result := FileExistsEx(FPath);
    if ASearchPaths = nil then
      ASearchPaths := AMainConv.FXRefSearchPaths;
    if not Result and (ASearchPaths <> nil) then
    begin
      vFileName := FPath;
      for I := 0 to ASearchPaths.Count - 1 do
      begin
        FPath := ForcePathSlash(ASearchPaths[I]);
        FPath := FPath + vFileName;
        Result := FileExists(FPath);
        if Result then
          Break;
      end;
    end
    else
    begin
      FPath := ForcePathSlash(GetCurrentDir) + ExtractFileName(AFilePath);
      Result := SysUtils.FileExists(FPath);
    end;
  end;
  if Result then
    try
      vPrevCADPreview := CADPreview;
      CADPreview := False;
      try
        I := XRefFileClasses.IndexOf(ExtractFileExt(FPath));
        if (I >= 0) and TGraphicClass(XRefFileClasses.Objects[I])
          .InheritsFrom(TsgCADImage) then
          with GlobalLoadingXRefsStack.LockList do
            try
              FCADImage := TGraphic(TGraphicClass(XRefFileClasses.Objects[I])
                .NewInstance);
              Add(Self);
              try
                // FCADImage.OnChange := GraphicChange;
                // if Assigned(Loading) and Assigned(Loading.OnProgress) then
                // if TObject(TMethod(Loading.OnProgress).Data) is TPicture then
                // FOwnerProgress := Loading.OnProgress;
                // FCADImage.OnProgress := ProgressEvent;
                FCADImage.Create;
                Converter.InitXRefConverter(TsgCADImage(FCADImage)
                  .Converter, Self);
                FCADImage.LoadFromFile(ExpandFileName(FPath));
                // Autodesk uses only DWG in Xref
              finally
                Remove(Self);
              end;
            finally
              GlobalLoadingXRefsStack.UnlockList;
            end;
      finally
        CADPreview := vPrevCADPreview;
      end;
    except
      Result := False;
      FreeCADImage;
    end;
  Name := ChangeFileExt(ExtractFileName(FPath), '');
end;

{ TsgDXFLayout }

constructor TsgDXFLayout.Create;
begin
  inherited Create;
  FBox := BadRect;
  Name := sModel;
  FPlotSettings := TsgDXFPlotSettings.Create;
  FCADSpace := cs3D; // cs2D - it is not completely tested for viewports
  FRotMatrix := cnstIdentityMat;
end;

function TsgDXFLayout.GetBlockName: string;
var
  I: Integer;
begin
  I := Self.Index;
  case I of
    - 1:
      Result := '*[' + Name + ']'; // need to correct!!!
    0:
      Result := sModelSpace;
    1:
      Result := sPaperSpace;
  else
    Result := sPaperSpace + IntToStr(I - 2);
  end;
end;

function TsgDXFLayout.GetBlockRecord: TsgDXFEntity;
begin
  Result := nil;
  if Assigned(FPaperSpaceBlock) then
    Result := FPaperSpaceBlock.BlockRecord;
end;

function TsgDXFLayout.GetBox: TFRect;
begin
  Result := FBox;
end;

function TsgDXFLayout.GetCount: Integer;
begin
  if FPaperSpaceBlock = nil then
    Result := 0
  else
    Result := PaperSpaceBlock.Count;
end;

function TsgDXFLayout.GetEntity(const AIndex: Integer): TsgDXFEntity;
begin
  if FPaperSpaceBlock = nil then
    Result := nil
  else
    Result := PaperSpaceBlock.Entities[AIndex];
end;

function TsgDXFLayout.GetExtMax: TFPoint;
begin
  Result := Box.BottomRight;
end;

function TsgDXFLayout.GetExtMin: TFPoint;
begin
  Result := Box.TopLeft;
end;

procedure TsgDXFLayout.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFLayout then
  begin
    FreeAndNil(FView);
    if Assigned(TsgDXFLayout(Source).FView) then
      GetView.AssignEntity(TsgDXFLayout(Source).FView);
    FPlotSettings.AssignEntity(TsgDXFLayout(Source).PlotSettings);
  end;
end;

function TsgDXFLayout.GetEmpty: Boolean;
begin
  Result := (Count = 0);
end;

function TsgDXFLayout.GetIndex: Integer;
begin
  // if Assigned(Owner) then
  // Result := Owner.IndexOfEntity(Self)
  // else
  // Result := -1;
  Result := -1;
  if Assigned(Converter) and Assigned(Converter.Sections[csLayouts]) then
    Result := Converter.Sections[csLayouts].IndexOfEntity(Self);
end;

function TsgDXFLayout.GetIsModel: Boolean;
begin
  Result := (Converter = nil) or
    ((Assigned(Converter)) and (Self = Converter.GetModelLayout));
end;

function TsgDXFLayout.GetLinMax: TFPoint;
begin
  Result := ExtMax;
end;

function TsgDXFLayout.GetLinMin: TFPoint;
begin
  Result := ExtMin;
end;

function TsgDXFLayout.GetPaperSpaceBlock: TsgDXFBlock;
var
  vBlock: TsgDXFBlock;
begin
  if (FPaperSpaceBlock = nil) and (Converter <> nil) then
  begin
    vBlock := TsgDXFBlock(Converter.NewNamedEntity(Converter.Sections[csBlocks],
      TsgDXFBlock, GetBlockName));
    Converter.SetHandle(vBlock);
    Converter.SetHandle(vBlock.BlockRecord);
    SetPaperSpaceBlock(vBlock);
  end;
  Result := FPaperSpaceBlock;
  if Assigned(Result) then
    Result.IsLoaded := False;
end;

// function TsgDXFLayout.GetPlotPaperUnits: Integer;
// begin
// Result := Integer(PlotSettings.PlotPaperUnits);
// end;

function TsgDXFLayout.GetView: TsgView;
begin
  if FView = nil then
    FView := TsgView.Create;
  Result := FView;
end;

{ TsgDXFLayout.IsgListOfEntities }

function TsgDXFLayout.DeleteEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := PaperSpaceBlock.DeleteEntity(AIndex);
end;

function TsgDXFLayout.AddEntity(const AEntity: TsgDXFEntity): Integer;
begin
  Result := PaperSpaceBlock.AddEntity(AEntity);
end;

procedure TsgDXFLayout.Clear(const ADoFree: Boolean = True);
begin
  if FPaperSpaceBlock <> nil then
    FPaperSpaceBlock.Clear(ADoFree);
end;

procedure TsgDXFLayout.ClearReferences;
begin
  inherited ClearReferences;
  PaperSpaceBlock := nil;
  if Assigned(FView) then
    FView.ClearView;
end;

function TsgDXFLayout.IndexOfEntity(const AEntity: TsgDXFEntity): Integer;
begin
  Result := PaperSpaceBlock.IndexOfEntity(AEntity);
end;

function TsgDXFLayout.IndexOfName(const AName: string): Integer;
begin
  Result := PaperSpaceBlock.IndexOfName(AName);
end;

function TsgDXFLayout.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  Result := PaperSpaceBlock.InsertEntity(AIndex, AEntity);
end;

procedure TsgDXFLayout.Iterate(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
{$IFDEF DEMO}
var
  vEnt: TsgDXFEntity;
{$ENDIF}
begin
  AConverter.Params^.Insert := nil;
  AConverter.Params^.ConvertMatrixCurrentIndertToWCS := cnstIdentityMat;
  AConverter.Params^.Color := clByLayer;
  AConverter.Params^.XScale := 0.0;
  AConverter.Params^.YScale := 0.0;
  AConverter.Params^.LType := StdLines;
  PaperSpaceBlock.Iterate(AConverter, Proc, FinishProc);
{$IFDEF DEMO}
  vEnt := DrawSGBlock(Self, AConverter);
  if vEnt is TsgDXFGroup then
    TsgDXFGroup(vEnt).Iterate(AConverter, Proc, FinishProc);
{$ENDIF}
end;

procedure TsgDXFLayout.LoadedInternal(AConverter: TsgDXFConverter);
var
  vEntity: TsgDXFEntity;
begin
  if Assigned(FPlotSettings) and (FPlotSettings.PageSetupName <> '') then
  begin
    vEntity := AConverter.Sections[csObjects].FindEntByName
      (FPlotSettings.PageSetupName);
    if (vEntity <> nil) and (vEntity <> FPlotSettings) then
      FPlotSettings.AssignEntity(vEntity);
  end;
  DoExtents(AConverter);
  inherited LoadedInternal(AConverter);
end;

function TsgDXFLayout.RotMatrix: TFMatrix;
begin
  Result := FRotMatrix;
end;

procedure TsgDXFLayout.SetRotMatrix(ARotMatrix: TFMatrix);
begin
  FRotMatrix := ARotMatrix;
end;

function TsgDXFLayout.UsingPlotSettings: Boolean;
begin
  Result := Assigned(FPlotSettings) and
    (FPlotSettings.PlotPaperSize.X * FPlotSettings.PlotPaperSize.Y <> 0);
end;

procedure TsgDXFLayout.DoExtents(AConverter: TsgDXFConverter);

  function IsInvisible(E: TsgDXFEntity): Boolean;
  var
    L: TsgDXFLayer;

    function IsBlockVisible(ABlock: TsgDXFBlock): Boolean;
    var
      EL: TsgDXFLayer;
      I: Integer;
    begin
      Result := False;
      for I := 0 to ABlock.Count - 1 do
      begin
        EL := TsgDXFEntity(ABlock.Entities[I]).Layer;
        if (EL <> nil) and (EL.Visible and not EL.IsFrozenByViewPort and
          not EL.Frozen) then
        begin
          Result := True;
          Break;
        end;
      end;
    end;

  begin
    Result := (E.EntType = ceEntity) or
      ((E is TsgDXFPoint) and (AConverter <> nil) and
      (AConverter.PointDisplayMode = 1)) or (not E.Visibility);
    if Result or (E is TsgDXFViewport) then
      Exit;
    L := E.Layer;
    Result := (L <> nil) and not(L.Visible and not L.Frozen);
    if Result and (L <> nil) and (not L.Frozen) and (E is TsgDXFInsert) and
      (TsgDXFInsert(E).Block <> nil) then
      Result := not IsBlockVisible(TsgDXFInsert(E).Block);
  end;

var
  I: Integer;
begin
  if FPaperSpaceBlock <> nil then
    FPaperSpaceBlock.IsLoaded := False;
  FBox := BadRect;
  for I := 0 to Count - 1 do
    if not IsInvisible(Entities[I]) then
      UnionFRect(FBox, Entities[I].Box);
end;

procedure TsgDXFLayout.SetBox(const ABox: TFRect);
begin
  FBox := ABox;
  if Assigned(FPaperSpaceBlock) then
    FPaperSpaceBlock.FBox := FBox;
end;

procedure TsgDXFLayout.SetEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity);
begin
  if FPaperSpaceBlock <> nil then
    PaperSpaceBlock.SetEntity(AIndex, AEntity);
end;

function TsgDXFLayout.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  if IsXMLHelp(AMode) then
    ANode.AddAttribNV(cnstXMLNames[xmlPaperSpaceBlock].Name)
  else if FPaperSpaceBlock <> nil then
    ANode.AddAttribNV(cnstXMLNames[xmlPaperSpaceBlock].Name).ValueAsStr :=
      FPaperSpaceBlock.Name;
  if IsFullPropsOrXMLHelp(AMode) or
    (not IsEqualFPoints(FUCSOrigin, cnstFPointZero)) then
    ANode.AddAttribNV(cnstXMLNames[xmlUCSOrigin].Name).ValueAsFPoint :=
      FUCSOrigin;
  if IsFullPropsOrXMLHelp(AMode) or
    (not IsEqualFPoints(FUCSXDir, cnstFPointZero)) then
    ANode.AddAttribNV(cnstXMLNames[xmlUCSXDir].Name).ValueAsFPoint := FUCSXDir;
  if IsFullPropsOrXMLHelp(AMode) or
    (not IsEqualFPoints(FUCSYDir, cnstFPointZero)) then
    ANode.AddAttribNV(cnstXMLNames[xmlUCSYDir].Name).ValueAsFPoint := FUCSYDir;
end;

procedure TsgDXFLayout.ToXMLSubEntities(const AParrentNode: TsgNode;
  const AMode: TsgXMLModes);
begin
  // no export sub entities
end;

procedure TsgDXFLayout.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FPlotSettings);
  FreeAndNil(FView);
end;

function TsgDXFLayout.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  vSectionBlocks: TsgDXFSectionBlocks;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlUCSOrigin:
      FUCSOrigin := ANode.ValueAsFPoint;
    xmlUCSXDir:
      FUCSXDir := ANode.ValueAsFPoint;
    xmlUCSYDir:
      FUCSYDir := ANode.ValueAsFPoint;
    xmlPaperSpaceBlock:
      begin
        vSectionBlocks := TsgDXFSectionBlocks(Converter.Sections[csBlocks]);
        if Assigned(vSectionBlocks) then
        begin
          if IsHandleStr(ANode.Value) then
            FPaperSpaceBlock :=
              TsgDXFBlock(vSectionBlocks.FindEntByHandle(ANode.ValueAsHandle))
          else
            FPaperSpaceBlock :=
              TsgDXFBlock(vSectionBlocks.FindEntByName(ANode.ValueAsStr));
        end;
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure TsgDXFLayout.SetPaperSpaceBlock(ABlock: TsgDXFBlock);
begin
  if FPaperSpaceBlock <> ABlock then
  begin
    if Assigned(FPaperSpaceBlock) then
      FPaperSpaceBlock.Layout := nil;
    FPaperSpaceBlock := ABlock;
    if Assigned(FPaperSpaceBlock) and
      (FPaperSpaceBlock.ClassType = TsgDXFBlockRecord) then
      FPaperSpaceBlock := TsgDXFBlockRecord(ABlock).Block;
    if Assigned(FPaperSpaceBlock) and
      (FPaperSpaceBlock.InheritsFrom(TsgDXFBlock)) then
      FPaperSpaceBlock.Layout := Self;
  end;
end;

//procedure TsgDXFLayout.SetPlotPaperUnits(const Value: Integer);
//begin
//  PlotSettings.PlotPaperUnits := TsgPlotPaperUnits(Value);
//end;

procedure TsgDXFLayout.SetPlotSettings(const Value: TsgDXFPlotSettings);
begin
  if Assigned(Value) then
    FPlotSettings.AssignEntity(Value);
end;

{ TsgImageDefPicture }

constructor TsgImageDefPicture.Create(AImageDef: TsgDXFImageDef);
begin
  inherited Create;
  FImageDef := AImageDef;
end;

destructor TsgImageDefPicture.Destroy;
begin
  FImageDef.FPicture := nil;
  FImageDef := nil;
  inherited Destroy;
end;

{ TsgDXFImageDef }

procedure TsgDXFImageDef.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFImageDef then
    FFileName := TsgDXFImageDef(Source).FFileName;
end;

function TsgDXFImageDef.EntName: string;
begin
  if Pos('/', FileName) > 0 then
    Result := ExtractWebFileName(FileName)
  else
    Result := ExtractFileName(FileName);
  Result := ChangeFileExt(Result, '');
  if Result = '' then
    Result := inherited EntName;
end;

procedure TsgDXFImageDef.ClearReferences;
var
  I: Integer;
begin
  inherited ClearReferences;
  if FReferences <> nil then
    for I := FReferences.Count - 1 downto 0 do
      TsgDXFEntity(FReferences[I]).RemoveReferenceNotification(Self);
end;

constructor TsgDXFImageDef.Create;
begin
  inherited Create;
  FPicture := TsgImageDefPicture.Create(Self);
end;

function TsgDXFImageDef.GetReferences: TsgList;
begin
  if FReferences = nil then
  begin
    FReferences := TsgList.Create;
    FReferences.Sorted := True;
    FReferences.Duplicates := dupIgnore;
  end;
  Result := FReferences;
end;

function TsgDXFImageDef.GetSize: TFPoint;
begin
  if FPicture.Graphic <> nil then
  begin
    Result.X := FPicture.Graphic.Width;
    Result.Y := FPicture.Graphic.Height;
    Result.Z := 0;
  end
  else
    Result := cnstFPointZero
end;

procedure TsgDXFImageDef.LoadedInternal(AConverter: TsgDXFConverter);
var
  BM: TsgBitMap;
begin
  inherited LoadedInternal(AConverter);
  try
    if IsFileOnWeb(FFileName) then
      LoadPictureFromWEB(FPicture, FFileName) // request INDY components
    else
      LoadPictureFromDisk(FPicture, FFileName);
    if not(FPicture.Graphic is TBitmap) then
      Exit;
    BM := TsgBitMap.Create;
    try
      BM.Assign(FPicture.Graphic);
      FPicture.Graphic := BM;
    finally
      BM.Free;
    end;
  except
  end;
end;

function TsgDXFImageDef.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlFileName].Name).ValueAsStr := FileName;
end;

procedure TsgDXFImageDef.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FReferences);
  FreeAndNil(FPicture);
end;

function TsgDXFImageDef.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlFileName:
      FileName := ANode.ValueAsStr;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

{ TsgDXFImageEnt }

procedure TsgDXFImageEnt.AssignEntity(Source: TsgDXFEntity);
var
  vImageEnt: TsgDXFImageEnt absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFImageEnt then
  begin
    if Assigned(vImageEnt.FImageProperties) then
    begin
      if not Assigned(FImageProperties) then
        New(FImageProperties);
      FImageProperties^ := vImageEnt.FImageProperties^;
    end
    else
      DisposeAndNil(FImageProperties);
    FreeAndNil(FBitMap);
    FFlagsEx := vImageEnt.FFlagsEx;
    ImageDef := vImageEnt.ImageDef;
    if not Assigned(FPicture) and Assigned(vImageEnt.Picture) and
      not vImageEnt.Picture.InheritsFrom(TsgImageDefPicture) then
    begin
      if Assigned(FImageDef) then
        FImageDef.References.Remove(Self);
      FImageDef := nil;
      FPicture := TPicture.Create;
      FPicture.Graphic := vImageEnt.Picture.Graphic;
    end;
    Transparency := vImageEnt.Transparency;
    TransparentColor := vImageEnt.TransparentColor;
{$IFDEF SG_USEGDIPLUS}
    GDIPFree;
{$ENDIF}
  end;
end;

function TsgDXFImageEnt.IsOnePixelOptimisationValid: Boolean; // evg
begin
  Result := False;
end;

function TsgDXFImageEnt.EntName: String;
begin
  Result := inherited EntName;
  if Picture <> nil then
    Result := Format('%s %d x %d', [Result, Picture.Width, Picture.Height]);
end;

procedure TsgDXFImageEnt.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(ImageDef) and (ImageDef.ClassType = TsgLinkObject) then
    ImageDef := TsgDXFImageDef(TsgLinkObject(ImageDef)
      .GetObject(AConverter.Sections[csImageDefs]));
end;

procedure TsgDXFImageEnt.LoadedInternal(AConverter: TsgDXFConverter);
begin
{$IFDEF SG_USEGDIPLUS}
  GDIPFree;
{$ENDIF}
  if FBitMap <> nil then
  begin
    FBitMap.Free;
    FBitMap := nil;
  end;
  if not Assigned(FPicture) and
    (Assigned(FImageDef) and Assigned(FImageDef.Picture) and
    Assigned(FImageDef.Picture.Graphic)) then
    SetImageDef(FImageDef);
  if Assigned(FPicture) and Assigned(FPicture.Graphic) then
  begin
    FPicture.Graphic.Transparent := Transparency;
    if FPicture.Graphic.InheritsFrom(Graphics.TBitmap) then
      Graphics.TBitmap(FPicture.Graphic).TransparentColor := TransparentColor;
  end;
  inherited LoadedInternal(AConverter);
end;

function TsgDXFImageEnt.PictureUpdate(const ACADImage: TObject): Boolean;
begin
  Result := False;
end;

procedure TsgDXFImageEnt.RemoveReferenceNotification(const ARefObj
  : TsgDXFEntity);
begin
  inherited RemoveReferenceNotification(ARefObj);
  if ARefObj = ImageDef then
    ImageDef := nil;
  if ARefObj = ImageDefExport then
    ImageDefExport := nil;
end;

procedure TsgDXFImageEnt.SetMnChrome(const AValue: Boolean);
begin
  FFlagsEx := (FFlagsEx and 254) or Byte(AValue);
end;

procedure TsgDXFImageEnt.SetMonoChrome;
begin
  IsMonoChrome := (FPicture <> nil) and (FPicture.Graphic is TBitmap) and
    FPicture.BitMap.Monochrome;
end;

procedure TsgDXFImageEnt.SetRotate(const Value: Double);
begin
end;

procedure TsgDXFImageEnt.SetTransparency(const Value: Boolean);
begin
  FFlags := (FFlags and -9) or (Byte(Value) shl 3);
end;

procedure TsgDXFImageEnt.SetTransparentColor(const AValue: Cardinal);
begin
  FTransparentColor := AValue;
end;

function TsgDXFImageEnt.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlTransparency].Name).ValueAsBool :=
    Transparency;
  ANode.AddAttribNV(cnstXMLNames[xmlTransparentColor].Name)
    .ValueData.ValueAsColor := TransparentColor;
  if IsXMLHelp(AMode) then
    ANode.AddAttribNV(cnstXMLNames[xmlImageDef].Name)
  else if Assigned(ImageDef) then
    ANode.AddAttribNV(cnstXMLNames[xmlImageDef].Name).ValueAsHandle :=
      ImageDef.Handle;
end;

procedure TsgDXFImageEnt.FreeReferences;
begin
  inherited FreeReferences;
{$IFDEF SG_USEGDIPLUS}
  GDIPFree;
{$ENDIF}
  DisposeAndNil(FImageProperties);
  FreeAndNil(FBitMap);
  if not(FPicture is TsgImageDefPicture) then
    FreeAndNil(FPicture);
end;

function TsgDXFImageEnt.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  vNode: TsgNodeSample;
  vImageDef: TsgDXFImageDef;
  vHandle: Int64;
  vVVector, vUVector: TFPoint;
  vMode: Integer;
  vWidth, vHeight, vAngle: Double;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlFileName:
      begin
        if FPicture = nil then
          FPicture := TPicture.Create;
        LoadPictureFromDisk(FPicture, ANode.ValueAsStr);
        if not(FPicture.Graphic is TBitmap) then
          Exit;
        ChangeGraphic;
        Size := MakeFPoint(FPicture.Graphic.Width, FPicture.Graphic.Height);
      end;
    xmlImageDef:
      begin
        vHandle := Converter.RestoreHandle(ANode);
        if vHandle <> cnstBadHandle then
        begin
          vImageDef := TsgDXFImageDef(Converter.Sections[csImageDefs]
            .FindEntByHandle(vHandle));
          if vImageDef <> nil then
          begin
            ImageDef := vImageDef;
            if Assigned(FPicture) and Assigned(FPicture.Graphic) then
              Size := MakeFPoint(FPicture.Graphic.Width,
                FPicture.Graphic.Height)
            else
              Size := cnstFPointZero;
          end;
        end;
      end;
    xmlTransparency:
      begin
        Transparency := ANode.ValueAsBool;
      end;
    xmlTransparentColor:
      begin
        TransparentColor := ANode.ValueData.ValueAsColor;
      end;
    xmlCalc:
      begin
        vNode := ANode.GetAttributeByName(cnstXMLNames[xmlMode].Name);
        if Assigned(vNode) then
        begin
          vMode := vNode.ValueAsInt;
          case vMode of
            0:
              begin
                vNode := ANode.GetAttributeByName(cnstXMLNames[xmlPoint1].Name);
                if Assigned(vNode) then
                begin
                  vVVector := vNode.ValueAsFPoint;
                  vNode := ANode.GetAttributeByName
                    (cnstXMLNames[xmlPoint2].Name);
                  if Assigned(vNode) and (Size.X * Size.Y <> 0) then
                  begin
                    if Size.X * Size.Y <> 0 then
                    begin
                      vUVector := vNode.ValueAsFPoint;
                      UVector := SubFPoint2D(vUVector, Point);
                      VVector := SubFPoint2D(vVVector, Point);
                      UVector := PtXScalar(UVector, 1 / Size.X);
                      VVector := PtXScalar(VVector, 1 / Size.Y);
                    end
                    else
                    begin
                      UVector := cnstXOrtAxis;
                      VVector := cnstYOrtAxis;
                    end;
                  end;
                end;
              end;
            1:
              begin
                vNode := ANode.GetAttributeByName(cnstXMLNames[xmlWidth].Name);
                if Assigned(vNode) then
                begin
                  vWidth := vNode.ValueAsDouble;
                  vNode := ANode.GetAttributeByName
                    (cnstXMLNames[xmlHeight].Name);
                  if Assigned(vNode) then
                  begin
                    vHeight := vNode.ValueAsDouble;
                    UVector := cnstXOrtAxis;
                    VVector := cnstYOrtAxis;
                    if Size.X * Size.Y <> 0 then
                    begin
                      vNode := ANode.GetAttributeByName
                        (cnstXMLNames[xmlAngle].Name);
                      if Assigned(vNode) then
                      begin
                        vAngle := vNode.ValueAsDouble;
                        if vAngle <> 0 then
                        begin
                          UVector := RotateFPoint(UVector, vAngle);
                          VVector := RotateFPoint(VVector, vAngle);
                        end;
                      end;
                      UVector := PtXScalar(UVector, vWidth / Size.X);
                      VVector := PtXScalar(VVector, vHeight / Size.Y);
                    end;
                  end;
                end;
              end;
          end;
        end;
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure TsgDXFImageEnt.SetImageDef(const Value: TsgDXFImageDef);
begin
  if Assigned(FPicture) then
    if FPicture.InheritsFrom(TsgImageDefPicture) then
      FPicture := nil
    else
      FreeAndNil(FPicture);
  if Assigned(FImageDef) and (FImageDef.ClassType <> TsgLinkObject) then
    FImageDef.References.Remove(Self);
  FImageDef := Value;
  if Assigned(FImageDef) and (FImageDef.ClassType <> TsgLinkObject) then
  begin
    FImageDef.References.Add(Self);
    FPicture := FImageDef.Picture;
    if (FPicture.Graphic = nil) or FPicture.Graphic.Empty then
      FPicture := nil;
    SetMonoChrome;
    SetDefaultTransparentColor(nil, Value);
  end;
end;

procedure TsgDXFImageEnt.SetImgLittle(const ABitmap: TBitmap);
begin
  if FBitMap <> nil then
    FBitMap.Free;
  FBitMap := TsgBitMap.Create;
  FBitMap.Assign(ABitmap);
end;

procedure TsgDXFImageEnt.SetInternal(const AValue: Boolean);
begin
  FFlagsEx := (FFlagsEx and 253) or (Byte(AValue) shl 1);
end;

procedure TsgDXFImageEnt.SetDefaultTransparentColor(const Image: TGraphic;
  const ImageDef: TsgDXFImageDef);
var
  vGraphic: TGraphic;
  vTransparency: Boolean;

begin
  TransparentColor := clWhite;
  if (Image = nil) and (ImageDef = nil) then
    Exit;
  vGraphic := nil;
  if ImageDef <> nil then
  begin
    if ImageDef.FPicture <> nil then
      vGraphic := ImageDef.FPicture.Graphic
  end
  else
    vGraphic := Image;
  vTransparency := Transparency;
  TransparentColor := GetColorByLeftTopPixel(vGraphic, vTransparency,
    TransparentColor);
  Transparency := vTransparency;
end;

procedure TsgDXFImageEnt.SetImage(Image: TGraphic);
begin
  if FPicture is TsgImageDefPicture then
    FPicture := nil;
  if FPicture = nil then
    FPicture := TPicture.Create;
  FPicture.Graphic := Image;
  SetMonoChrome;
  SetDefaultTransparentColor(Image, nil);
end;

function TsgDXFImageEnt.GetEntType: TsgCADEntities;
begin
  Result := ceImageEnt;
end;

function TsgDXFImageEnt.GetInternal: Boolean;
begin
  Result := (FFlagsEx and 2) <> 0;
end;

function TsgDXFImageEnt.GetMnChrome: Boolean;
begin
  Result := (FFlagsEx and 1) <> 0;
end;

{$IFDEF SG_USEGDIPLUS}

procedure TsgDXFImageEnt.GDIPCreate;
var
  vIStream: IStream;
  vBuffer: Pointer;
  vMemoryStream: TMemoryStream;

  procedure ConvertTosgBitmap;
  var
    vBitmap: TsgBitMap;
    vBMP: TBitmap;
    vColor: array [0 .. 1] of TRGBQuad;
    vNeedConvert: Boolean;
  begin
    vNeedConvert := FPicture.Graphic is TsgBitMap;
    ChangeGraphic;
    vBitmap := TsgBitMap(FPicture.Graphic);
    case vBitmap.PixelFormat of
      pf1Bit:
        begin
          // fix by chahge color for gdi+ drawing
          if vNeedConvert and (TsgBitmapAccess(vBitmap).FROP <> SRCCOPY) then
          begin
            FillChar(vColor, 8, 0);
            FillChar(vColor[0], 4, 255);
            vBitmap.SetColors(@vColor[0]);
          end;
        end;
      pfCustom, pfDevice:
        begin
          vBMP := TBitmap.Create;
          try
            SetSizeBmp(vBMP, vBitmap.Width, vBitmap.Height);
            vBMP.PixelFormat := pf24bit;
            vBMP.Canvas.Draw(0, 0, vBitmap);
            vBitmap.Assign(vBMP);
          finally
            vBMP.Free;
          end;
        end;
    end;
    // FGDIPImage := TsgGDIPlusImage(TsgGDIPlusBitmap.Create(vBitMap.Width, vBitMap.Height,
    // vBitMap.RowSize, GetPixelFormat(vBitMap.PixelFormat), vBitMap.ScanLine[0]));
    FGDIPImage := TsgGDIPlusImage
      (TsgGDIPlusBitmap.Create(vBitmap.ImageData.Info, vBitmap.ImageData.Data));
  end;

begin
  if (FGDIPImage <> nil) or (FPicture = nil) or (FPicture.Graphic = nil) then
    Exit;
  if GetAnimate then
  begin
    vMemoryStream := TMemoryStream.Create;
    try
      FPicture.Graphic.SaveToStream(vMemoryStream);
      vMemoryStream.Position := 0;
      FGDIDataHandle := GlobalAlloc(GMEM_MOVEABLE, vMemoryStream.Size);
      if FGDIDataHandle <> 0 then
      begin
        vBuffer := GlobalLock(FGDIDataHandle);
        if vBuffer <> nil then
          Move(vMemoryStream.Memory^, vBuffer^, vMemoryStream.Size)
        else
        begin
          GlobalFree(FGDIDataHandle);
          FGDIDataHandle := 0;
        end;
      end;
    finally
      vMemoryStream.Free;
    end;
    if FGDIDataHandle <> 0 then
    begin
      GlobalUnlock(FGDIDataHandle);
      if Succeeded(CreateStreamOnHGlobal(FGDIDataHandle, False, vIStream)) then
        FGDIPImage := TsgGDIPlusImage(TsgGDIPlusBitmap.Create(vIStream))
      else
      begin
        GlobalFree(FGDIDataHandle);
        FGDIDataHandle := 0;
        ConvertTosgBitmap;
      end;
    end
    else
      ConvertTosgBitmap;
  end
  else
  begin
    if Picture.Graphic is TMetafile then
      FGDIPImage := TsgGDIPlusImage
        (TsgGDIPlusMetaFile.Create(TMetafile(Picture.Graphic).Handle, False))
    else
      ConvertTosgBitmap;
  end;
  if FGDIPImage.GetStatusOfFunction <> Ok then
    GDIPFree;
end;

procedure TsgDXFImageEnt.GDIPFree;
var
  vGDIPImage: TsgGDIPlusImage;
begin
  if FGDIPImage <> nil then
  begin
    vGDIPImage := FGDIPImage;
    FGDIPImage := nil;
    vGDIPImage.Free;
  end;
  if FGDIDataHandle <> 0 then
  begin
    GlobalFree(FGDIDataHandle);
    FGDIDataHandle := 0;
  end;
end;
{$ENDIF}

procedure TsgDXFImageEnt.ChangeGraphic;
var
  vBitmap: TsgBitMap;
  vBtmp: Graphics.TBitmap;

  procedure ChangeGraphicUseBitMap(const AGraphic: TGraphic);
  var
    vBMP: Graphics.TBitmap;
  begin
    vBMP := Graphics.TBitmap(CreateCopyGraphicAsBitmap(FPicture.Graphic));
    try
      if vBMP <> nil then
        vBitmap.Assign(vBMP);
    finally
      vBMP.Free;
    end;
  end;

begin
  if (FPicture.Graphic = nil) or (FPicture.Graphic is TsgBitMap) then
    Exit;
  vBitmap := TsgBitMap.Create;
  try
    if FPicture.Graphic is TBitmap then
    begin
      try
        if Graphics.TBitmap(FPicture.Graphic).PixelFormat in [pfDevice, pfCustom]
        then
        begin
          vBtmp := Graphics.TBitmap.Create;
          try
            vBtmp.PixelFormat := pf24bit;
            SetSizeBmp(vBtmp, FPicture.Graphic.Width, FPicture.Graphic.Height);
            vBtmp.Canvas.StretchDraw(vBtmp.Canvas.ClipRect, FPicture.Graphic);
            vBitmap.Assign(vBtmp);
          finally
            vBtmp.Free;
          end;
        end
        else
          vBitmap.Assign(FPicture.Graphic);
      except
        ChangeGraphicUseBitMap(FPicture.Graphic);
      end;
    end
    else
    begin
{$IFNDEF SGFPC}
      if FPicture.Graphic.ClassType <> TMetafile then
      begin
{$ENDIF}
        vBtmp := Graphics.TBitmap.Create;
        try
          vBtmp.Assign(FPicture.Graphic);
          vBitmap.Assign(vBtmp);
          vBtmp.Free;
        except
          vBtmp.Free;
          ChangeGraphicUseBitMap(FPicture.Graphic);
        end;
{$IFNDEF SGFPC}
      end
      else
        ChangeGraphicUseBitMap(FPicture.Graphic);
{$ENDIF}
    end;
  finally
    FPicture.Graphic := vBitmap;
    vBitmap.Free;
  end;
end;

procedure TsgDXFImageEnt.ClearReferences;
begin
  inherited ClearReferences;
  ImageDefExport := nil;
  ImageDef := nil;
end;

constructor TsgDXFImageEnt.Create;
begin
  inherited Create;
  FFlags := 3;
  FDirectExportConverImageToOLE := False;
  FDirectExportImageFileIndex := -1;
  SetDefaultTransparentColor(nil, nil);
end;

procedure TsgDXFImageEnt.CreateImgLittle(const Scale: Integer);
var
  vBMP: Graphics.TBitmap;
  vMax: Integer;
  vSize: Double;
  vPixelFormat: Graphics.TPixelFormat;

  function CreateLittleBitmapBy1pxl: Boolean;
  var
    vBitmap: TsgBitMap;
  begin
    ChangeGraphic;
    vBitmap := TsgBitMap(FPicture.Graphic);
    if (vBitmap.PixelFormat = pf1Bit) then
    begin
      case Scale of
        4:
          begin
            FScaleMode := 4;
            CreatesgBitMapBy1pxlDiv4(vBitmap, TsgBitMap(FBitMap));
          end;
        8:
          begin
            FScaleMode := 8;
            CreatesgBitMapBy1pxlDiv8(vBitmap, TsgBitMap(FBitMap));
          end;
      end;
      Result := True;
    end
    else
      Result := False;
  end;

begin
  FScaleMode := 0;
  if FBitMap <> nil then
  begin
    FBitMap.Free;
    FBitMap := nil;
  end;
  if (FPicture <> nil) and (FPicture.Graphic <> nil) then
  begin
    try
      vSize := FPicture.Graphic.Width * FPicture.Graphic.Height;
      if vSize / cnstMaxImgSizeSqrt > 1.20 then
      begin
        if FPicture.Graphic is TBitmap then
        begin
          vPixelFormat := TBitmap(FPicture.Graphic).PixelFormat;
          if (vPixelFormat = pf1Bit) and CreateLittleBitmapBy1pxl then
            Exit;
        end
        else if FPicture.Graphic is TsgBitMap then
        begin
          vPixelFormat := TsgBitMap(FPicture.Graphic).PixelFormat;
          if (vPixelFormat = pf1Bit) and CreateLittleBitmapBy1pxl then
            Exit;
        end
        else
          vPixelFormat := pf24bit;
        vBMP := Graphics.TBitmap.Create;
        try
          vMax := MaxI(FPicture.Graphic.Width, FPicture.Graphic.Height);
          vBMP.PixelFormat := vPixelFormat;
          vBMP.Width := cnstMaxImgSize * FPicture.Graphic.Width div vMax;
          vBMP.Height := cnstMaxImgSize * FPicture.Graphic.Height div vMax;
          vBMP.Canvas.StretchDraw(Rect(0, 0, vBMP.Width, vBMP.Height),
            FPicture.Graphic);
          SetImgLittle(vBMP);
        finally
          vBMP.Free;
        end;
      end;
    finally
      if FBitMap <> nil then
        FBitMap.Transparent := Transparency;
    end;
  end;
end;

function TsgDXFImageEnt.DoRotate(const Angle: Double;
  const AConverter: TsgDXFConverter): Boolean;
var
  vAngle: Integer;
  vDelta, vDP1, vDP2: TFPoint;
  vOldWidth: Double;
begin
  Result := False;
  vAngle := (Round(sgMod(Angle, 360)) div 90) * 90;
  if vAngle <> 0 then
  begin
    if (FPicture = nil) or (FPicture is TsgImageDefPicture) then
    begin
      FPicture := TPicture.Create;
      FPicture.Assign(ImageDef.Picture);
      FreeAndNil(FBitMap);
    end;

    ChangeGraphic;
    vOldWidth := TsgBitMap(FPicture.Graphic).Width;
    if FBitMap <> nil then
      TsgBitMap(FBitMap).Rotate(vAngle);
    TsgBitMap(FPicture.Graphic).Rotate(vAngle);

    vDP1 := MiddleFPoint(Point1, Point2);
    FUVector := RotateFPoint(FUVector, vAngle);
    FVVector := RotateFPoint(FVVector, vAngle);
    FSize := AbsFPoint(RotateFPoint(FSize, vAngle));
    vDP2 := MiddleFPoint(Point1, Point2);
    vDelta := SubFPoint(vDP1, vDP2);
    Point := AddFPoint(Point, vDelta);

    if FClippingBoundaryType = 1 then
    begin
      if vOldWidth <> TsgBitMap(FPicture.Graphic).Width then
      begin
        if FClipPoints.Count >= 2 then
        begin
          SwapSGFloats(PF2DPoint(FClipPoints[0])^.X,
            PF2DPoint(FClipPoints[0])^.Y);
          SwapSGFloats(PF2DPoint(FClipPoints[1])^.X,
            PF2DPoint(FClipPoints[1])^.Y);
        end;
      end;
    end;

    Result := True;
    if AConverter <> nil then
      LoadedInternal(AConverter);
  end;
end;

function TsgDXFImageEnt.GetAnimate: Boolean;
begin
  Result := False;
end;

function TsgDXFImageEnt.GetBoxPoints(Proc: TFPointProc; Full: Boolean): Boolean;
begin
  // Result := inherited GetBoxPoints(Proc, Full);// for future versions
  Proc(Point);
  Proc(Point1);
  Proc(Point2);
  Proc(Point3);
  Result := False; // See CADImage.DrawPoly (!)
end;

function TsgDXFImageEnt.GetRotate: Double;
begin
  Result := 0;
end;

function TsgDXFImageEnt.GetTransparency: Boolean;
begin
  Result := (FFlags and 8) <> 0;
end;

function TsgDXFImageEnt.GetTransparentColor: Cardinal;
begin
  Result := FTransparentColor;
end;

function TsgDXFImageEnt.GroupCountEntities: Integer;
var
  vGr: TGraphic;
  vBitmap: TsgBitmapAccess;
  vChunk, vChunkRes: TPoint;

begin
  Result := 0;
  if (Picture = nil) or (Picture.Graphic = nil) then
    Exit;
  vGr := Picture.Graphic;
{$IFNDEF SGFPC}
  if vGr is TMetafile then
    if CheckExportOLEAsMetafile(TMetafile(vGr).Handle) then
      Exit;
{$ENDIF}
  vBitmap := TsgBitmapAccess.Create;
  try
    vBitmap.Assign(vGr);
    vChunk := GetCountBlocksForOLEExport(vBitmap.Width, vBitmap.Height,
      vBitmap.PixelFormat, vChunkRes);
    if (vChunk.X >= 0) and (vChunk.Y >= 0) then
      Result := (vChunk.X + 1) * (vChunk.Y + 1);
  finally
    vBitmap.Free;
  end;
end;

function TsgDXFImageEnt.GroupExists: Boolean;
var
  vIndex: Integer;
begin
  vIndex := GetExportImageIndex(Self, FDirectExportImageFileIndex,
    FDirectExportConverImageToOLE);
  if vIndex = cntImageExportAsOLE2Frame then
    Result := GroupCountEntities > 1
  else
    Result := False;
end;

function TsgDXFImageEnt.GroupFill(AConverter: TsgDXFConverter = nil): Boolean;
var
  I, vCount: Integer;
  vPoint: TsgDXFPoint;
begin
  if AConverter <> nil then
  begin
    vCount := GroupCountEntities;
    for I := 0 to vCount - 1 do
    begin
      vPoint := TsgDXFPoint.Create;
      vPoint.Loaded(AConverter);
      Group.AddEntity(vPoint);
    end;
  end;
  Result := Group.Count > 0;
end;

function TsgDXFImageEnt.GroupHasAddedEntities: Boolean;
begin
  Result := True;
end;

procedure TsgDXFImageEnt.ApplyBox;
begin
  inherited ApplyBox;
  ExpandFRect(FBox, Point);
  ExpandFRect(FBox, Point1);
  ExpandFRect(FBox, Point2);
  ExpandFRect(FBox, Point3);
end;

{ TsgDXFStyle }

procedure TsgDXFStyle.AssignEntity(Source: TsgDXFEntity);
var
  vStyle: TsgDXFStyle absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFStyle then
  begin
    FBigFont := vStyle.FBigFont;
    FFlags := vStyle.FFlags;
    FFixedHeight := vStyle.FFixedHeight;
    FFontName := vStyle.FontName;
    FFontStyle := vStyle.FontStyle;
    FLastHeightUsed := vStyle.FLastHeightUsed;
    FObliqueAngle := vStyle.FObliqueAngle;
    FPrimaryFont := vStyle.FPrimaryFont;
    FSHXStyle := nil;
    FTextGenFlags := vStyle.FTextGenFlags;
    FWidthFactor := vStyle.FWidthFactor;
  end;
end;

function TsgDXFStyle.BeginExtData(const AData: TsgCADExtendedData): Boolean;
begin
  AData.AddString(String_1001, sACADXDataAppName);
  Result := True;
end;

constructor TsgDXFStyle.Create;
begin
  inherited Create;
  Name := sStandardName;
  FWidthFactor := 1.0;
  FLastHeightUsed := 2.5;
  FPrimaryFont := 'txt';
end;

procedure TsgDXFStyle.EndExtData(const AData: TsgCADExtendedData);
begin
end;

function TsgDXFStyle.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlWidthFactor:
      FWidthFactor := ANode.ValueAsDouble;
    xmlObliqueAngle:
      FObliqueAngle := ANode.ValueAsDouble;
    xmlTextGenFlags:
      FTextGenFlags := ANode.ValueAsInt;
    xmlLastHeightUsed:
      FLastHeightUsed := ANode.ValueAsDouble;
    xmlPrimaryFont:
      FPrimaryFont := ANode.ValueAsStr;
    xmlBigFont:
      FBigFont := ANode.ValueAsStr;
    xmlFontName:
      FFontName := ANode.ValueAsStr;
    xmlFixedHeight:
      FFixedHeight := ANode.ValueAsDouble;
    xmlFontStyle:
      FFontStyle := IntegerToFontStyles(ANode.ValueAsInt);
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFStyle.GetBackward: Boolean;
begin
  Result := (FTextGenFlags and 2) <> 0;
end;

function TsgDXFStyle.GetExtData(const AData: TsgCADExtendedData): Boolean;
var
  vFontStyle: Integer;
  vFontName: string;

  function IsPrimaryFontFile: Boolean;
  begin
    Result := AnsiPos('.TTF', AnsiUpperCase(FPrimaryFont)) > 0;
  end;

begin
  Result := False;
  if (FontName <> '') or IsPrimaryFontFile then
  begin
    vFontName := FontName;
    if vFontName = '' then
      vFontName := GetFontNameWithoutStyle
        (GetFontNameByFileName(GetPrimaryFontName));
    BeginExtData(AData);
    AData.AddString(String_1000, vFontName);
    vFontStyle := 0;
    if fmItalic in FontStyle then
      vFontStyle := vFontStyle or $1000000;
    if fmBold in FontStyle then
      vFontStyle := vFontStyle or $2000000;
    AData.AddInt(Integer_1071, vFontStyle);
    EndExtData(AData); // do nothing
    Result := AData.DataCount > 0;
  end;
end;

function TsgDXFStyle.GetPrimaryFontName: string;
begin
  Result := '';
  if Length(FPrimaryFont) > 0 then
    Result := ExtractFileName(FPrimaryFont);
end;

function TsgDXFStyle.GetUpsideDown: Boolean;
begin
  Result := (FTextGenFlags and 4) <> 0;
end;

procedure TsgDXFStyle.LoadedInternal(AConverter: TsgDXFConverter);
var
  vPos: Integer;
  vPrimaryFont, vName: string;
begin
  inherited LoadedInternal(AConverter);
  if FWidthFactor < fAccuracy then // FWidthFactor = 0
    FWidthFactor := 1.0;
  // export already check this flag!!!
  // if FFlags and 1 <> 0 then
  // FName := '';// SHAPE style name must be empty (see SHX and export to DXF)
  if FFontName = '' then
  begin
    vPrimaryFont := GetPrimaryFontName;
    vPos := AnsiPos('.TTF', UpperCase(vPrimaryFont));
    if vPos > 0 then
    begin
      FFontName := GetFontNameByFileName(vPrimaryFont);
      if Length(FFontName) > 0 then
      begin
        FFontStyle := GetFontStyleByFontName(FFontName);
        FFontName := GetFontNameWithoutStyle(FFontName);
        if Length(FFontName) = 0 then
          FFontName := Copy(vPrimaryFont, 1, vPos - 1);
      end;
    end
    else if vPrimaryFont <> '' then
    begin
      // For future versions
      // FSHXStyle := AConverter.FSHXFonts.AddStyle(FName, FPrimaryFont, FBigFont, FFlags and 4 <> 0,
      // UpsideDown, Backward, FObliqueAngle, FWidthFactor);
    end
    else
      FPrimaryFont := sDefaultSHXFont;
  end;
  vName := '';
  if FFlags and 1 = 0 then
    vName := Name;
  FSHXStyle := AConverter.FSHXFonts.AddStyle(vName, FPrimaryFont, FBigFont,
    FFlags and 4 <> 0, UpsideDown, Backward, FObliqueAngle, FWidthFactor);
end;

procedure TsgDXFStyle.SetBackward(const AValue: Boolean);
begin
  FTextGenFlags := (FTextGenFlags and 253) or Integer(AValue) shl 1;
end;

procedure TsgDXFStyle.SetPrimaryFont(const AValue: string);
begin
  FPrimaryFont := AValue; // can have full file path
end;

procedure TsgDXFStyle.SetUpsideDown(const AValue: Boolean);
begin
  FTextGenFlags := (FTextGenFlags and 251) or Integer(AValue) shl 2;
end;

function TsgDXFStyle.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlWidthFactor].Name).ValueAsDouble :=
    FWidthFactor;
  ANode.AddAttribNV(cnstXMLNames[xmlObliqueAngle].Name).ValueAsDouble :=
    FObliqueAngle;
  ANode.AddAttribNV(cnstXMLNames[xmlTextGenFlags].Name).ValueAsInt :=
    FTextGenFlags;
  ANode.AddAttribNV(cnstXMLNames[xmlLastHeightUsed].Name).ValueAsDouble :=
    FLastHeightUsed;
  if (Length(FPrimaryFont) > 0) or IsXMLHelp(AMode) then
    ANode.AddAttribNV(cnstXMLNames[xmlPrimaryFont].Name).ValueAsStr :=
      FPrimaryFont;
  if (Length(FBigFont) > 0) or IsXMLHelp(AMode) then
    ANode.AddAttribNV(cnstXMLNames[xmlBigFont].Name).ValueAsStr := FBigFont;
  if (Length(FFontName) > 0) or IsXMLHelp(AMode) then
    ANode.AddAttribNV(cnstXMLNames[xmlFontName].Name).ValueAsStr := FFontName;
  ANode.AddAttribNV(cnstXMLNames[xmlFixedHeight].Name).ValueAsDouble :=
    FFixedHeight;
  ANode.AddAttribNV(cnstXMLNames[xmlFontStyle].Name).ValueAsInt :=
    FontStylesToInteger(FFontStyle);
end;

{ TsgDXFACISEntity }

procedure TsgDXFACISEntity.Clear(const ADoFree: Boolean);
begin
  inherited Clear(ADoFree);
  if Assigned(FBrepRoot) then
    FreeAndNil(FBrepRoot);
  if Assigned(FIndexFaceMap) then
    FreeAndNil(FIndexFaceMap);
  FParcingConverter := nil;
end;

procedure TsgDXFACISEntity.ClearReferences;
begin
  inherited ClearReferences;
  FProprietaryData.Clear;
end;

constructor TsgDXFACISEntity.Create;
begin
  inherited Create;
  FEncoded := True;
  FProprietaryDataDecoded := False;
  FDelimiter := sSatDelimiter0;
  FEofStr := sSatEofStr;
  FSATDirect := False;
  FIncorrectAttribsChecked := False;
  FProprietaryData := TStringList.Create;
end;

procedure TsgDXFACISEntity.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FProprietaryData);
end;

function TsgDXFACISEntity.GroupExists: Boolean;
begin
  Result := True;
end;

procedure TsgDXFACISEntity.AssignEntity(Source: TsgDXFEntity);
var
  vACIS: TsgDXFACISEntity absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFACISEntity then
  begin
    Clear;
    ProprietaryData := vACIS.ProprietaryData;
    FEncoded := vACIS.FEncoded;
    FProprietaryDataDecoded := vACIS.ProprietaryDataDecoded;
    FDelimiter := vACIS.Delimiter;
    FEofStr := vACIS.EofStr;
    FSATDirect := vACIS.SATDirect;
    FIncorrectAttribsChecked := vACIS.FIncorrectAttribsChecked;
  end;
end;

{$IFDEF SG_CADIMPORTER_DLL}

type
  TsgSATParserAccess = class(TsgSATParser);
{$ENDIF}

procedure TsgDXFACISEntity.LoadedInternal(AConverter: TsgDXFConverter);
{ In order to write the CoEdgeReversed (is the entity reversed) the polylines
  inheritors use the fourth flag bit. A number of the loop to which an entity
  belongs is written into the handle of this entity.
}
var
  vParser: TsgSATParser;
{$IFDEF SG_CADIMPORTER_DLL}
  I: Integer;
  S: string;
{$ENDIF}
begin
  FBox := BadRect;
  if Layer = nil then
    Layer := FPen.Layer;
  if Layer = nil then
    Layer := AConverter.LayerByName('0');
  if not Assigned(FBrepRoot) then
  begin
    Clear;
    vParser := TsgSATParser.Create(AConverter);
    try
      FBrepRoot := TsgDXFEntity(TsgBrepRoot.Create);
      FIndexFaceMap := TList.Create;
      FParcingConverter := AConverter;
      vParser.Parse(Self);
{$IFDEF SG_CADIMPORTER_DLL}
      FSATStrings := '';
      for I := 0 to TsgSATParserAccess(vParser).SATStringsCount - 1 do
      begin
        S := TsgSATParserAccess(vParser).SATStringsClear[I];
        if S <> '' then
          FSATStrings := FSATStrings + S + #13;
      end;
{$ENDIF}
    finally
      vParser.Free;
    end;
  end;
  inherited LoadedInternal(AConverter);
end;

procedure TsgDXFACISEntity.LoadFromFile(const FileName: string);
var
  vFileStream: TFileStream;
begin
  FDelimiter := ' ';
  FEofStr := sSatEofStr;
  vFileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  try
    LoadFromStream(vFileStream);
  finally
    vFileStream.Free;
  end;
end;

procedure TsgDXFACISEntity.LoadFromMemory(Mem: Pointer; Size: Integer;
  ASATDirect: Boolean = True);
var
  vStream: TMemoryStream;
begin
  vStream := TMemoryStream.Create;
  try
    vStream.Write(Mem^, Size);
    LoadFromStream(vStream, ASATDirect);
  finally
    vStream.Free;
  end;
end;

procedure TsgDXFACISEntity.LoadFromStream(const AStream: TStream;
  ASATDirect: Boolean = True);
var
  vOldPos: Cardinal;
  vData: sgRawByteString;
  vBinConv: TsgSATBinToTxtConv;
  vSize: Integer;
begin
  Clear;
  ProprietaryData.Text := '';
  vOldPos := AStream.Position;
  try
    AStream.Position := 0;
    vSize := AStream.Size;
    SetLength(vData, vSize);
    AStream.Read(vData[1], vSize);
    if IsSatBinaryFile(@vData[1], vSize) then
    begin
      vBinConv := TsgSATBinToTxtConv.CreateFromMemory(@vData[1], vSize);
      try
        if vBinConv.Convert(Delimiter, EofStr) then
          ProprietaryData.Text := vBinConv.SatText
        else
          ProprietaryData.Text := '';
      finally
        vBinConv.Free;
      end;
    end
    else
      ProprietaryData.Text := string(vData);
  finally
    AStream.Position := vOldPos;
  end;
  if ProprietaryData.Text <> '' then
  begin
    FProprietaryDataDecoded := True;
    FSATDirect := ASATDirect;
    FIncorrectAttribsChecked := True;
  end;
end;

procedure TsgDXFACISEntity.MeshBrepBuilder(const AInitParam: TsgInitParam;
  const AData: TsgInitMeshBuilderData;
  const ADeviationCoefficien: Double = 0.001);

const
  cntMaxLoopsCount = 50;

var
  I, J, K, M, N, L, S: Integer;
  vLump: TsgBrepLump;
  vBody: TsgBody;
  vShell: TsgBrepShell;
  vFace: TsgBrepFace;
  vLoop: TsgBrepLoop;
  vCoEdge: TsgBrepCoEdge;
  vEdge: TsgBrepEdge;
  vParams: TsgDLLParam;
  vFlag: Boolean;
  vBrep: TsgBrepRoot;
  vBeginData: TsgBeginData;
  vEndData: TsgEndMakeShapeData;
  vContext: PsgContext;
  vWireData: TsgWireData;
  vInitOrientation: Boolean;

  // Index: Integer;

  function GetPerformOffAllFlagsFlag(Face: TsgBrepFace): Integer;
  begin
    Result := 0;
    if (Face <> nil) and (Face.Loops.Count > cntMaxLoopsCount) then
      Result := 1;
  end;

  function CallsgEndMakeShape: Integer;
  begin
    vEndData.GetTriangleFunc := AData.TriangleFunc;
    vParams.GetTriangleFuncParam := AData.MeshParam;
    vEndData.Params := @vParams;
    vEndData.NewFaceGroupFunc := AData.NewFaceGroupFunc;
    vEndData.BeginSegment := AData.BeginSegment;
    vEndData.EndSegment := AData.EndSegment;
    Result := sgEndMakeShape(vContext, vEndData);
  end;

  procedure BeginSegment(AIndexFaceMap: Integer = -1);
  begin
    if Assigned(AInitParam.Creator) then
      TsgCreatorEntityBase(AInitParam.Creator).BeginSegment(cnstColorCADByBlock,
        AIndexFaceMap);
  end;

  procedure EndSegment;
  begin
    if Assigned(AInitParam.Creator) then
      TsgCreatorEntityBase(AInitParam.Creator).EndSegment;
  end;

begin
  vBrep := TsgBrepRoot(Brep);

  if AData.TriangleFunc <> nil then
  begin
    vFace := TsgBrepFace(FIndexFaceMap.List[AData.IndexFaceMap]);
    vContext := vFace.GetContex;
    if vContext.Context <> nil then
    begin
      sgInitParser(vContext, AInitParam);
      CallsgEndMakeShape;
    end;
    inherited MeshBrepBuilder(AInitParam, AData, ADeviationCoefficien);
    Exit;
  end;

  FIndexFaceMap.Clear;

  // Index := 0;
  // vTickStarted := GetTickCount;
  BeginSegment;
  for I := 0 to vBrep.Body.Count - 1 do
  begin
    vBody := TsgBody(vBrep.Body[I]);
    for J := 0 to vBody.Lumps.Count - 1 do
    begin
      vLump := vBody.Lumps[J];
      for K := 0 to vLump.Shell.Count - 1 do
      begin
        vShell := TsgBrepShell(vLump.Shell[K]);
        BeginSegment;

        for M := 0 to vShell.Face.Count - 1 do
        begin
          vFlag := False;
          vFace := TsgBrepFace(vShell.Face[M]);
          if Assigned(vFace.Sufface) then
          begin
            vContext := vFace.GetContex;
            if vContext.Context <> nil then
            begin
              sgInitParser(vContext, AInitParam);
              CallsgEndMakeShape;
              Continue;
            end;
            sgInitContext(vContext);
            sgInitParser(vContext, AInitParam);
            vBeginData.PointX := MakeVertex(vBody.Matrix.EX);
            vBeginData.PointY := MakeVertex(vBody.Matrix.EY);
            vBeginData.PointZ := MakeVertex(vBody.Matrix.EZ);
            vBeginData.Point0 := MakeVertex(vBody.Matrix.E0);
            vBeginData.MatrixPlus := vBody.MatrixPlus;
            vBeginData.PerformOffAllFlags := GetPerformOffAllFlagsFlag(vFace);
            // seSphereSurface   sePlaneSurface seTorusSurface  seConeSurface seExactSplineSurface
            // if vFace.Sufface.BrepEntType <> seTorusSurface then
            // Continue;
            // if vFace.Sufface.BrepEntType = seTorusSurface then
            // begin
            // Inc(Index);
            // if not((Index >= 22) and (Index <= 22) ) then//if not ((Index = 2) or (Index = 4)) then  //16
            // Continue;
            // end;

            sgBeginMakeShape(vContext, vBeginData);

            // OutputDebugString(PChar(Format('   Face - %s', [vFace.Sufface.ClassName])));

            if vBrep.AddSurfaceToBrepBuilder(vContext, vFace) then
            begin
              vFlag := True;
              FIndexFaceMap.Add(vFace);
              BeginSegment(FIndexFaceMap.Count - 1);
            end
            else
            begin
              ZeroMemory(@vEndData, SizeOf(vEndData));
              sgEndMakeShape(vContext, vEndData);
            end;
          end;

          for N := 0 to vFace.Loops.Count - 1 do
          begin
            if vFlag then
            begin
              sgBeginWire(vContext);
              vLoop := TsgBrepLoop(vFace.Loops[N]);

              vWireData.EdgeReverse := 0;
              vWireData.CoEdgeReverse := 0;
              vInitOrientation := False;

              for L := 0 to vLoop.CoEdges.Count - 1 do
              begin
                vCoEdge := TsgBrepCoEdge(vLoop.CoEdges[L]);
                for S := 0 to vCoEdge.Edges.Count - 1 do
                begin
                  vEdge := TsgBrepEdge(vCoEdge.Edges[S]);

                  if vFlag then // Add only cone surface
                  begin
                    if vBrep.AddCurveToBrepBuilder(vContext, vEdge,
                      vCoEdge.Orientation) and (not vInitOrientation) then
                    begin
                      vWireData.CoEdgeReverse := vCoEdge.Orientation;
                      vWireData.EdgeReverse := vEdge.Orientation;
                      vInitOrientation := True;
                    end;
                  end;

                  // for P := 0 to vEdge.Vertices.Count - 1 do
                  // begin
                  // vVertices := TsgBrepVertices(vEdge.Vertices[P]);
                  // end;
                end;
              end;
              sgEndWire(vContext, vWireData)
            end;
          end;

          if vFlag then
          begin
            if RESULT_ERROR = CallsgEndMakeShape then
            begin
              EndSegment;
              sgFreeContext(vContext);
              vContext.Context := nil;
            end
            else
            begin
              EndSegment;
            end;
          end;
        end;
        EndSegment;
      end;
    end;
  end;
  EndSegment;
  inherited MeshBrepBuilder(AInitParam, AData, ADeviationCoefficien);
end;

procedure TsgDXFACISEntity.SetProprietaryData(const AValue: TStringList);
begin
  FProprietaryData.Assign(AValue);
  FreeAndNil(FBrepRoot);
  FreeAndNil(FIndexFaceMap);
end;

{ TsgDXFRegion }

function TsgDXFRegion.GetEntType: TsgCADEntities;
begin
  Result := ceRegion;
end;

procedure TsgDXFRegion.LoadedInternal(AConverter: TsgDXFConverter);
begin
  sgLockCallMeshBuilder;
  try
    inherited LoadedInternal(AConverter);
  finally
    sgUnLockCallMeshBuilder;
  end;
end;

{ TsgDXFBody }

function TsgDXFBody.GetEntType: TsgCADEntities;
begin
  Result := ceBody;
end;

{ TsgDXF3DSolid }

function TsgDXF3dSolid.GetEntType: TsgCADEntities;
begin
  Result := ce3DSolid;
end;

{ TsgAcadTableCell }

procedure TsgAcadTableCell.Assign(ASource: TPersistent);
var
  I: Integer;
  vCell: TsgAcadTableCell;
begin
  if ASource is ClassType then
  begin
    vCell := TsgAcadTableCell(ASource);
    FAutoFit := vCell.AutoFit;
    FBlockRecordHandle := vCell.BlockRecordHandle;
    FBlockScale := vCell.BlockScale;
    Field := vCell.Field;
    FFlags := vCell.Flags;
    FIsTextType := vCell.IsTextType;
    FMergedHeight := vCell.MergedHeight;
    FMergedValue := vCell.MergedValue;
    FMergedWidth := vCell.MergedWidth;
    FNumAttdefs := vCell.NumAttdefs;
    FOverrideFlag := vCell.OverrideFlag;
    FRotation := vCell.Rotation;
    FText := vCell.Text;
    FAttdefHandle := vCell.AttdefHandle;
    FVirtualEgdeFlag := vCell.VirtualEgdeFlag;
    FCol := vCell.Col;
    FRow := vCell.Row;
    FSpanX := vCell.SpanX;
    FSpanY := vCell.SpanY;
    FCellProps.Assign(vCell.FCellProps);
    for I := 0 to 5 do
      UpdateFlags(I);
  end
  else
    inherited Assign(ASource);
end;

constructor TsgAcadTableCell.Create(AAcadTable: TsgDXFAcadTable;
  const ACol, ARow: Integer; const ACellType: TsgAcadTableCellType);
begin
  FAcadTable := AAcadTable;
  if Assigned(FAcadTable) then
    FCellProps := TsgAcadTableCellStyle.Create(FAcadTable.Properties, ACellType)
  else
    FCellProps := TsgAcadTableCellStyle.Create(nil, ACellType);
  FIsTextType := True;
  FCol := ACol;
  FRow := ARow;
  FMergedValue := 0;
  FMergedWidth := 1;
  FMergedHeight := 1;
end;

destructor TsgAcadTableCell.Destroy;
begin
  Field := nil;
  FreeAndNil(FCellProps);
  inherited Destroy;
end;

function TsgAcadTableCell.GenerateMText(const AConv: TsgDXFConverter;
  const AAcadTable: TsgDXFAcadTable): TsgDXFMText;
var
  vAcadTableGenerator: TsgAcadTableGenerator;
begin
  Result := nil;
  if Assigned(AAcadTable) and Assigned(AConv) then
  begin
    vAcadTableGenerator := TsgAcadTableGenerator.Create(AConv, AAcadTable);
    try
      Result := vAcadTableGenerator.CreateMText(Self, False, True);
    finally
      vAcadTableGenerator.Free;
    end;
  end;
end;

function TsgAcadTableCell.GetBaseCell: TsgAcadTableCell;
begin
  Result := Self;
  if not IsBaseCell and Assigned(FAcadTable) then
    Result := FAcadTable.Cell[FCol - FSpanX, FRow - FSpanY];
end;

function TsgAcadTableCell.GetBaseCellRange: TRect;
var
  vBaseCell: TsgAcadTableCell;
begin
  if IsBaseCell then
    Result := CellRange
  else
  begin
    vBaseCell := BaseCell;
    Result := Rect(vBaseCell.Col, vBaseCell.Row,
      vBaseCell.Col + vBaseCell.SpanX, vBaseCell.Row + vBaseCell.SpanY);
  end;
end;

function TsgAcadTableCell.GetBkColorOn: Boolean;
begin
  Result := StyleByProp(cpBkColorOn).BkColorOn;
end;

function TsgAcadTableCell.GetBorderColor(Index: Integer): TsgColorCAD;
var
  vOverride: Boolean;
begin
  vOverride := IsBorderColorOverriden(Index);
  if not vOverride and HasOwnerStyle then
    Result := GetOwnerStyle.BorderColor[Index]
  else
    Result := FCellProps.BorderColor[Index]
end;

function TsgAcadTableCell.GetBorderLineWeight(Index: Integer): Double;
var
  vOverride: Boolean;
begin
  vOverride := IsBorderLineweightOverriden(Index);
  if not vOverride and HasOwnerStyle then
    Result := GetOwnerStyle.BorderLineWeight[Index]
  else
    Result := FCellProps.BorderLineWeight[Index]
end;

function TsgAcadTableCell.GetBorderPropOverridenMask(const ABorderProp
  : TsgBorderProp; const AIndex: Integer): Integer;
const
  // 0 - horizontal inside ??
  // 1 - right border
  // 2 - bottom border
  // 3 - vertical inside ??
  // 4 - left border
  // 5 - top border
  cnstShiftVal: array [0 .. 5] of Integer = (0, 1, 2, 0, 3, 0);
begin
  if AIndex in [0, 3] then
    Result := 0
  else
    Result := ($40 shl (Ord(ABorderProp) shl 2)) shl cnstShiftVal[AIndex];
end;

function TsgAcadTableCell.GetBorderVisible(Index: Integer): Boolean;
var
  vOverride: Boolean;
begin
  vOverride := IsBorderVisibleOverriden(Index);
  if not vOverride and HasOwnerStyle then
    Result := GetOwnerStyle.BorderVisible[Index]
  else
    Result := FCellProps.BorderVisible[Index]
end;

function TsgAcadTableCell.GetCellAlignment: Integer;
begin
  Result := StyleByProp(cpCellAllignment).CellAlignment;
end;

function TsgAcadTableCell.GetCellRange: TRect;
begin
  Result := Rect(FCol, FRow, FCol, FRow);
end;

function TsgAcadTableCell.GetCellType: TsgAcadTableCellType;
begin
  if HasOwnerStyle then
  begin
    case FRow of
      0:
        Result := cttTitle;
      1:
        Result := cttHeader;
    else
      Result := cttData;
    end;
  end
  else
    Result := FCellType;
end;

function TsgAcadTableCell.GetDataType: Integer;
begin
  Result := StyleByProp(cpDataType).DataType;
end;

function TsgAcadTableCell.GetFillColor: TsgColorCAD;
begin
  Result := StyleByProp(cpFillColor).FillColor;
end;

function TsgAcadTableCell.GetFlags: Integer;
begin
  Result := FFlags;
end;

function TsgAcadTableCell.GetFlagsMask(AIndex: Integer): Integer;
const
  // 1:  right
  // 2:  bottom
  // 4:  left
  // 5:  top
  cnstMasks: array [0 .. 5] of Integer = (0, $02, $04, 0, $08, $01);
begin
  Result := cnstMasks[AIndex];
end;

function TsgAcadTableCell.GetIsBaseCell: Boolean;
begin
  Result := FMergedValue = 0;
end;

function TsgAcadTableCell.GetMerged: Boolean;
begin
  Result := (FSpanX > 0) or (FSpanY > 0);
end;

function TsgAcadTableCell.GetMergedRect: TFRect;
var
  vBaseCell: TsgAcadTableCell;
  I: Integer;
begin
  if IsBaseCell and not Merged then
    Result := GetRect
  else
  begin
    vBaseCell := BaseCell;
    Result := vBaseCell.GetRect;
    for I := vBaseCell.Col + 1 to vBaseCell.Col + vBaseCell.MergedWidth - 1 do
      Result.Right := Result.Right + AcadTable.ColWidth[I];
    for I := vBaseCell.Row + 1 to vBaseCell.Row + vBaseCell.MergedHeight - 1 do
      Result.Bottom := Result.Bottom - AcadTable.RowHeight[I];
  end;
end;

function TsgAcadTableCell.GetOwnerStyle: TsgAcadTableCellStyle;
begin
  Result := AcadTable.Style.CellStyle[CellType];
end;

function TsgAcadTableCell.GetRect: TFRect;
var
  I: Integer;
begin
  FillChar(Result, SizeOf(TFRect), 0);
  I := 0;
  while I < FCol do
  begin
    Result.Left := Result.Left + AcadTable.ColWidth[I];
    Inc(I);
  end;
  Result.Right := Result.Left + AcadTable.ColWidth[I];
  I := 0;
  while I < FRow do
  begin
    Result.Top := Result.Top - AcadTable.RowHeight[I];
    Inc(I);
  end;
  Result.Bottom := Result.Top - AcadTable.RowHeight[I];
end;

function TsgAcadTableCell.GetTextColor: TsgColorCAD;
begin
  Result := StyleByProp(cpTextColor).TextColor;
end;

function TsgAcadTableCell.GetTextHeight: Double;
begin
  if (FOverrideFlag and $20 = 0) and HasOwnerStyle then
    Result := GetOwnerStyle.TextHeight
  else
    Result := FCellProps.TextHeight;
end;

function TsgAcadTableCell.GetTextStyle: TsgDXFStyle;
begin
  Result := StyleByProp(cpTextStyle).TextStyle;
end;

function TsgAcadTableCell.GetUnitType: Integer;
begin
  Result := StyleByProp(cpUnitType).UnitType;
end;

function TsgAcadTableCell.IsBorderColorOverriden(const AIndex: Integer)
  : Boolean;
begin
  Result := IsBorderPropOverriden(bpColor, AIndex);
end;

function TsgAcadTableCell.IsBorderEq(const AIndex: Integer;
  const ACell: TsgAcadTableCell): Boolean;
begin
  Result := IsBorderEqEx(AIndex, ACell, AIndex);
end;

function TsgAcadTableCell.IsBorderEqEx(const AIndex: Integer;
  const AAdjacentCell: TsgAcadTableCell; const AAdjacentIndex: Integer)
  : Boolean;
begin
  Result := (BorderVisible[AIndex] = AAdjacentCell.BorderVisible[AAdjacentIndex]
    ) and IsColorCADEqual(BorderColor[AIndex],
    AAdjacentCell.BorderColor[AAdjacentIndex]) and
    (BorderLineWeight[AIndex] = AAdjacentCell.BorderLineWeight[AAdjacentIndex]);
end;

function TsgAcadTableCell.IsBorderLineweightOverriden
  (const AIndex: Integer): Boolean;
begin
  Result := IsBorderPropOverriden(bpLineweight, AIndex);
end;

function TsgAcadTableCell.IsBorderPropOverriden(const ABorderProp
  : TsgBorderProp; const AIndex: Integer): Boolean;
var
  vMask: Integer;
begin
  vMask := GetBorderPropOverridenMask(ABorderProp, AIndex);
  Result := (FOverrideFlag and vMask <> 0) or (AIndex in [0, 3]);
end;

function TsgAcadTableCell.IsBorderVisibleOverriden(const AIndex
  : Integer): Boolean;
begin
  Result := IsBorderPropOverriden(bpVisible, AIndex);
end;

function TsgAcadTableCell.IsPropInit(const ACellProp: TsgCellProp): Boolean;
begin
  Result := FCellProps.IsPropInit(ACellProp);
end;

procedure TsgAcadTableCell.Link(AConverter: TsgDXFConverter);
begin
  if Assigned(TextStyle) and (TextStyle.ClassType = TsgLinkObject) then
    TextStyle := TsgDXFStyle(TsgLinkObject(TextStyle)
      .GetObject(AConverter.Sections[csStyles]));
end;

function TsgAcadTableCell.HasOwnerStyle: Boolean;
begin
  Result := Assigned(FAcadTable) and Assigned(FAcadTable.Style);
end;

procedure TsgAcadTableCell.SetAttdefHandle(const AValue: UInt64);
begin
  FAttdefHandle := AValue;
end;

procedure TsgAcadTableCell.SetAttdefValue(const AValue: string);
begin
  FAttdefValue := AValue;
end;

procedure TsgAcadTableCell.SetAutoFit(const AValue: Boolean);
begin
  FAutoFit := AValue;
end;

procedure TsgAcadTableCell.SetBkColorOn(const AValue: Boolean);
begin
  FCellProps.BkColorOn := AValue;
  FCellProps.SetPropInit(cpBkColorOn, True);
  if HasOwnerStyle and GetOwnerStyle.BkColorOn = FCellProps.BkColorOn then
    FCellProps.SetPropInit(cpBkColorOn, False);
end;

procedure TsgAcadTableCell.SetBlockRecordHandle(const AValue: UInt64);
begin
  FBlockRecordHandle := AValue;
end;

procedure TsgAcadTableCell.SetBlockScale(const AValue: Single);
begin
  FBlockScale := AValue;
end;

procedure TsgAcadTableCell.SetBorderColor(Index: Integer;
  const AValue: TsgColorCAD);
var
  vMaskOverrideFlag: Integer;
begin
  vMaskOverrideFlag := GetBorderPropOverridenMask(bpColor, Index);
  FCellProps.BorderColor[Index] := AValue;
  if HasOwnerStyle and IsColorCADEqual(GetOwnerStyle.BorderColor[Index],
    FCellProps.BorderColor[Index]) then
    FOverrideFlag := FOverrideFlag and not vMaskOverrideFlag
  else
    FOverrideFlag := FOverrideFlag or vMaskOverrideFlag;
  UpdateFlags(Index);
end;

procedure TsgAcadTableCell.SetBorderLineWeight(Index: Integer;
  const AValue: Double);
var
  vMaskOverrideFlag: Integer;
begin
  vMaskOverrideFlag := GetBorderPropOverridenMask(bpLineweight, Index);
  FCellProps.BorderLineWeight[Index] := AValue;
  if HasOwnerStyle and (GetOwnerStyle.BorderLineWeight[Index]
    = FCellProps.BorderLineWeight[Index]) then
    FOverrideFlag := FOverrideFlag and not vMaskOverrideFlag
  else
    FOverrideFlag := FOverrideFlag or vMaskOverrideFlag;
  UpdateFlags(Index);
end;

procedure TsgAcadTableCell.SetBorderVisible(Index: Integer;
  const AValue: Boolean);
var
  vMaskOverrideFlag: Integer;
begin
  vMaskOverrideFlag := GetBorderPropOverridenMask(bpVisible, Index);
  FCellProps.BorderVisible[Index] := AValue;
  if HasOwnerStyle and
    (GetOwnerStyle.BorderVisible[Index] = FCellProps.BorderVisible[Index]) then
    FOverrideFlag := FOverrideFlag and not vMaskOverrideFlag
  else
    FOverrideFlag := FOverrideFlag or vMaskOverrideFlag;
  UpdateFlags(Index);
end;

procedure TsgAcadTableCell.SetCellAlignment(const AValue: Integer);
begin
  FCellProps.CellAlignment := AValue;
  FCellProps.SetPropInit(cpCellAllignment, True);
  if HasOwnerStyle and (GetOwnerStyle.CellAlignment = FCellProps.CellAlignment)
  then
    FCellProps.SetPropInit(cpCellAllignment, False);
end;

procedure TsgAcadTableCell.SetCellType(const AValue: TsgAcadTableCellType);
begin
  FCellType := AValue;
end;

procedure TsgAcadTableCell.SetDataType(const AValue: Integer);
begin
  FCellProps.DataType := AValue;
  FCellProps.SetPropInit(cpDataType, True);
  if HasOwnerStyle and (GetOwnerStyle.DataType = FCellProps.DataType) then
    FCellProps.SetPropInit(cpDataType, False);
end;

procedure TsgAcadTableCell.SetField(const AValue: TsgDXFField);
begin
  FField := AValue;
end;

procedure TsgAcadTableCell.SetFillColor(const AValue: TsgColorCAD);
begin
  FCellProps.FillColor := AValue;
  FCellProps.SetPropInit(cpFillColor, True);
  if HasOwnerStyle and IsColorCADEqual(GetOwnerStyle.FillColor,
    FCellProps.FillColor) then
    FCellProps.SetPropInit(cpFillColor, False);
  BkColorOn := not IsColorCADEqual(MakeColorCAD(acIndexColor, clDXFBlackWhite),
    FCellProps.FillColor);
end;

procedure TsgAcadTableCell.SetFlags(const AValue: Integer);
begin
  FFlags := AValue;
end;

procedure TsgAcadTableCell.SetIsBaseCell(const AValue: Boolean);
begin
  FMergedValue := Ord(not AValue);
end;

procedure TsgAcadTableCell.SetIsTextType(const AValue: Boolean);
begin
  FIsTextType := AValue;
end;

procedure TsgAcadTableCell.SetMergedHeight(const AValue: Integer);
begin
  FMergedHeight := AValue;
end;

procedure TsgAcadTableCell.SetMergedValue(const AValue: Integer);
begin
  FMergedValue := AValue;
end;

procedure TsgAcadTableCell.SetMergedWidth(const AValue: Integer);
begin
  FMergedWidth := AValue;
end;

procedure TsgAcadTableCell.SetNumAttdefs(const AValue: Integer);
begin
  FNumAttdefs := AValue;
end;

procedure TsgAcadTableCell.SetOverrideFlag(const AValue: Integer);
begin
  FOverrideFlag := AValue;
end;

procedure TsgAcadTableCell.SetRotation(const AValue: Single);
begin
  FRotation := AValue;
end;

procedure TsgAcadTableCell.SetText(const AValue: string);
begin
  FText := AValue;
end;

procedure TsgAcadTableCell.SetTextColor(const AValue: TsgColorCAD);
begin
  FCellProps.TextColor := AValue;
  FCellProps.SetPropInit(cpTextColor, True);
  if HasOwnerStyle and IsColorCADEqual(GetOwnerStyle.TextColor,
    FCellProps.TextColor) then
    FCellProps.SetPropInit(cpTextColor, False);
end;

procedure TsgAcadTableCell.SetTextHeight(const AValue: Double);
begin
  FCellProps.TextHeight := AValue;
  FOverrideFlag := FOverrideFlag or $20;
  if HasOwnerStyle and (GetOwnerStyle.TextHeight = FCellProps.TextHeight) then
    FOverrideFlag := FOverrideFlag and not $20;
end;

procedure TsgAcadTableCell.SetTextStyle(const AValue: TsgDXFStyle);
begin
  FCellProps.TextStyle := AValue;
  FCellProps.SetPropInit(cpTextStyle, True);
  if HasOwnerStyle and (GetOwnerStyle.TextStyle = FCellProps.TextStyle) then
    FCellProps.SetPropInit(cpTextStyle, False);
end;

procedure TsgAcadTableCell.SetUnitType(const AValue: Integer);
begin
  FCellProps.UnitType := AValue;
  FCellProps.SetPropInit(cpUnitType, True);
  if HasOwnerStyle and (GetOwnerStyle.UnitType = FCellProps.UnitType) then
    FCellProps.SetPropInit(cpUnitType, False);
end;

procedure TsgAcadTableCell.SetVirtualEgdeFlag(const AValue: Boolean);
begin
  FVirtualEgdeFlag := AValue;
end;

function TsgAcadTableCell.StyleByProp(const ACellProp: TsgCellProp)
  : TsgAcadTableCellStyle;
begin
  if not IsPropInit(ACellProp) and HasOwnerStyle then
    Result := GetOwnerStyle
  else
    Result := FCellProps;
end;

procedure TsgAcadTableCell.UpdateFlags(const AIndex: Integer);
var
  I: TsgBorderProp;
  vSetBit: Boolean;
begin
  I := Low(TsgBorderProp);
  vSetBit := False;
  while not vSetBit and (I <= High(TsgBorderProp)) do
    if IsBorderPropOverriden(I, AIndex) then
      Inc(vSetBit)
    else
      Inc(I);
  if vSetBit then
    FFlags := FFlags or GetFlagsMask(AIndex)
  else
    FFlags := FFlags and not GetFlagsMask(AIndex)
end;

{ TsgDXFAcadTable }

procedure TsgDXFAcadTable.SetNumCols(const AValue: Integer);
begin
  if FColWidth.Count <> AValue then
    Resize(AValue, FRowHeight.Count);
end;

procedure TsgDXFAcadTable.SetRowHeight(Index: Integer; const AValue: Double);
begin
  FRowHeight[Index] := AValue;
end;

procedure TsgDXFAcadTable.SetSizes(ANeedRowSize: Boolean; Index: Integer;
  const AValue: Double);
begin
  case ANeedRowSize of
    False:
      ColWidth[Index] := AValue;
    True:
      RowHeight[Index] := AValue;
  end;
end;

procedure TsgDXFAcadTable.SetStyle(const AValue: TsgDXFAcadTableStyle);
begin
  if FStyleRef <> AValue then
  begin
    FStyleRef := AValue;
    if Assigned(FStyleRef) and (FStyleRef.ClassType <> TsgLinkObject) then
      EnumCells(SetCellTextStyle, FStyleRef);
  end;
end;

procedure TsgDXFAcadTable.SplitCells(ACol, ARow: Integer);
var
  vBC: TsgAcadTableCell;
begin
  vBC := Cell[ACol, ARow].BaseCell;
  EnumRange(Rect(vBC.Col, vBC.Row, vBC.Col + vBC.MergedWidth - 1,
    vBC.Row + vBC.MergedHeight - 1), SplitCell, vBC);
end;

function TsgDXFAcadTable.SplitCell(ACol, ARow: Integer;
  AParam: Pointer): Boolean;
var
  vCell: TsgAcadTableCell;
begin
  Result := True;
  vCell := Cell[ACol, ARow];
  vCell.IsBaseCell := True;
  vCell.MergedWidth := 1;
  vCell.MergedHeight := 1;
  vCell.SpanX := 0;
  vCell.SpanY := 0;
end;

procedure TsgDXFAcadTable.SetCell(ACol, ARow: Integer;
  const AValue: TsgAcadTableCell);
begin
  Cell[ACol, ARow].Assign(AValue);
end;

function TsgDXFAcadTable.SetCellTextStyle(ACol, ARow: Integer;
  AParam: Pointer): Boolean;
begin
  Result := True;
  if not Cell[ACol, ARow].IsPropInit(cpTextStyle) then
    Cell[ACol, ARow].FCellProps.TextStyle := TsgDXFAcadTableStyle(AParam)
      .CellStyle[Cell[ACol, ARow].CellType].TextStyle;
end;

procedure TsgDXFAcadTable.SetColWidth(Index: Integer; const AValue: Double);
begin
  FColWidth[Index] := AValue;
end;

procedure TsgDXFAcadTable.SetFlags(const AValue: Integer);
begin
  FFlags := AValue;
end;

procedure TsgDXFAcadTable.SetNumRows(const AValue: Integer);
begin
  if FRowHeight.Count <> AValue then
    Resize(FColWidth.Count, AValue);
end;

{ Method TsgDXFAcadTable.SetOverrideFlags

  0 bit: Flag for an override                       (93)
  1 bit: Flag for an override of border color       (94)
  2 bit: Flag for an override of border lineweight  (95)
  3 bit: Flag for an override of border visibility  (96) }
procedure TsgDXFAcadTable.SetOverrideFlags(const AValue: Byte);
begin
  FOverrideFlags := AValue;
end;

procedure TsgDXFAcadTable.SetProperties(const AValue: TsgDXFAcadTableStyle);
begin
  FProperties.AssignEntity(AValue);
end;

procedure TsgDXFAcadTable.AssignEntity(Source: TsgDXFEntity);
var
  vAcadTable: TsgDXFAcadTable;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFAcadTable then
  begin
    vAcadTable := TsgDXFAcadTable(Source);
    FStyleRef := vAcadTable.Style;
    Properties := vAcadTable.Properties;
    Resize(vAcadTable.NumCols, vAcadTable.NumRows);
    FColWidth.Assign(vAcadTable.FColWidth);
    FRowHeight.Assign(vAcadTable.FRowHeight);
    EnumCells(AssignCell, vAcadTable);
  end;
end;

function TsgDXFAcadTable.AddCol: Integer;
begin
  Result := NumCols;
  InsertCol(Result);
end;

function TsgDXFAcadTable.AddRow: Integer;
begin
  Result := NumRows;
  InsertRow(Result);
end;

function TsgDXFAcadTable.AssignCell(ACol, ARow: Integer;
  AParam: Pointer): Boolean;
begin
  Result := True;
  Cell[ACol, ARow] := TsgDXFAcadTable(AParam).Cell[ACol, ARow];
end;

procedure TsgDXFAcadTable.Clear(const ADoFree: Boolean = True);
var
  vList: TListNotify;
begin
  if Assigned(FColWidth) then
    FColWidth.Clear;
  if Assigned(FRowHeight) then
    FRowHeight.Clear;
  if Assigned(FRows) then
    while FRows.Count > 0 do
    begin
      vList := FRows.Last;
      ClearEntCollection(vList, ADoFree);
      vList.Free;
      FRows.Delete(FRows.Count - 1);
    end;
end;

procedure TsgDXFAcadTable.ClearReferences;
begin
  inherited ClearReferences;
  Style := nil;
end;

constructor TsgDXFAcadTable.Create;
begin
  inherited Create;
  FRows := TList.Create;
  FColWidth := TsgDoubleList.Create;
  FRowHeight := TsgDoubleList.Create;
  FProperties := TsgDXFAcadTableStyle.Create;
  FLockGenerateBlock := False;
end;

function TsgDXFAcadTable.CreateBlock(AConv: TsgDXFConverter): TsgDXFBlock;
begin
  Result := TsgDXFBlock.Create;
  AConv.DoCreate(Result);
  Result.Name := GetUniqueBlockName(AConv);
  AConv.Sections[csBlocks].AddEntity(Result);
  Block := Result;
end;

procedure TsgDXFAcadTable.DeleteCol(ACol: Integer);
var
  R: Integer;
  vList: TListNotify;
  vCell: TsgAcadTableCell;
begin
  for R := 0 to NumRows - 1 do
  begin
    vList := FRows[R];
    vCell := vList[ACol];
    vList.Delete(ACol);
    vCell.Free;
  end;
  FColWidth.Delete(ACol);
end;

procedure TsgDXFAcadTable.DeleteCols(AColFrom, AColTo: Integer);
var
  C: Integer;
begin
  for C := AColTo downto AColFrom do
    DeleteCol(C);
end;

procedure TsgDXFAcadTable.DeleteRow(ARow: Integer);
var
  vRow: TListNotify;
begin
  vRow := FRows[ARow];
  FRows.Delete(ARow);
  ClearEntCollection(vRow, True);
  FRowHeight.Delete(ARow);
end;

procedure TsgDXFAcadTable.DeleteRows(ARowFrom, ARowTo: Integer);
var
  R: Integer;
begin
  for R := ARowTo downto ARowFrom do
    DeleteRow(R);
end;

function TsgDXFAcadTable.EnumCells(AEnumCellsProc: TsgEnumCellsProc;
  AParam: Pointer): Boolean;
begin
  Result := EnumRange(Rect(0, 0, NumCols - 1, NumRows - 1),
    AEnumCellsProc, AParam);
end;

function TsgDXFAcadTable.EnumRange(ARange: TRect;
  AEnumCellsProc: TsgEnumCellsProc; AParam: Pointer): Boolean;
var
  R, C: Integer;
  vStopEnum: Boolean;
begin
  vStopEnum := False;
  if Assigned(AEnumCellsProc) then
  begin
    R := ARange.Top;
    while not vStopEnum and (R <= ARange.Bottom) do
    begin
      C := ARange.Left;
      while not vStopEnum and (C <= ARange.Right) do
        if AEnumCellsProc(C, R, AParam) then
          Inc(C)
        else
          Inc(vStopEnum);
      Inc(R, Ord(not vStopEnum));
    end;
  end;
  Result := not vStopEnum;
end;

procedure TsgDXFAcadTable.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FProperties);
  FreeAndNil(FColWidth);
  FreeAndNil(FRowHeight);
  FreeAndNil(FRows);
end;

function TsgDXFAcadTable.GetNumRows: Integer;
begin
  Result := FRowHeight.Count;
end;

function TsgDXFAcadTable.GetPropertiesAcadTableStyle: TsgDXFAcadTableStyle;
begin
  Result := FProperties;
end;

function TsgDXFAcadTable.GetRowHeight(Index: Integer): Double;
begin
  if Index >= FRowHeight.Count then
  begin
    if FRowHeight.Count = 0 then
    begin
      if Assigned(Converter) then
        Result := Converter.HeadVarStruct.TextSize + 2 * fCellMargin
      else
        Result := cnstDefHeadVarStruct.TextSize + 2 * fCellMargin;
    end
    else
      Result := FRowHeight.Last
  end
  else if Index >= 0 then
    Result := FRowHeight[Index]
  else
    Result := 0;
end;

function TsgDXFAcadTable.GetSizes(ANeedRowSize: Boolean;
  Index: Integer): Double;
begin
  if ANeedRowSize then
    Result := RowHeight[Index]
  else
    Result := ColWidth[Index];
end;

function TsgDXFAcadTable.GetStyle: TsgDXFAcadTableStyle;
begin
  Result := FStyleRef;
end;

function TsgDXFAcadTable.GetUniqueBlockName(const AConv
  : TsgDXFConverter): string;
var
  vBlocks: TsgDXFTable;
begin
  // generate unique block name
  vBlocks := TsgDXFTable(AConv.Sections[csBlocks]);
  repeat
    Inc(AConv.FAddedTablesCount);
    Result := sInternalACADTable + IntToStr(AConv.FAddedTablesCount);
  until not Assigned(vBlocks.FindEntByName(Result));
end;

procedure TsgDXFAcadTable.InsertCol(AIndex: Integer);
var
  R: Integer;
begin
  for R := 0 to NumRows - 1 do
    TList(FRows[R]).Insert(AIndex, nil);
  FColWidth.Insert(AIndex, ColWidth[AIndex]);
end;

procedure TsgDXFAcadTable.InsertRow(AIndex: Integer);
var
  vList: TList;
begin
  vList := TListNotify.Create;
  try
    vList.Count := NumCols;
    FRows.Insert(AIndex, vList);
  except
    vList.Free;
    raise;
  end;
  FRowHeight.Insert(AIndex, RowHeight[AIndex]);
end;

function TsgDXFAcadTable.IsBlockInternal: Boolean;
begin
  Result := not Assigned(Block) or
    (AnsiPos(sInternalACADTable, TryLinkToName(Block)) = 1);
end;

function TsgDXFAcadTable.GetNumCols: Integer;
begin
  Result := FColWidth.Count;
end;

function TsgDXFAcadTable.GenerateMText(const AConv: TsgDXFConverter;
  ACol, ARow: Integer): TsgDXFMText;
begin
  Result := Cell[ACol, ARow].GenerateMText(AConv, Self);
end;

function TsgDXFAcadTable.GetBaseCell(ACol, ARow: Integer): TsgAcadTableCell;
begin
  Result := Cell[ACol, ARow].BaseCell;
end;

function TsgDXFAcadTable.GetCell(ACol, ARow: Integer): TsgAcadTableCell;
var
  vCellType: TsgAcadTableCellType;
begin
  if ARow < 0 then
    ARow := 0
  else if ARow >= NumRows then
    ARow := NumRows - 1;
  if ACol < 0 then
    ACol := 0
  else if ACol >= NumCols then
    ACol := NumCols - 1;
  Result := TList(FRows[ARow])[ACol];
  if not Assigned(Result) then
  begin
    case ARow of
      0:
        vCellType := cttTitle;
      1:
        vCellType := cttHeader;
    else
      vCellType := cttData;
    end;
    Result := TsgAcadTableCell.Create(Self, ACol, ARow, vCellType);
    TList(FRows[ARow])[ACol] := Result;
  end;
end;

function TsgDXFAcadTable.GetColWidth(Index: Integer): Double;
const
  cnstSymCount = 10;
begin
  if Index >= FColWidth.Count then
  begin
    if FColWidth.Count = 0 then
    begin
      if Assigned(Converter) then
        Result := cnstSymCount * (Converter.HeadVarStruct.TextSize + 2 *
          fCellMargin)
      else
        Result := cnstSymCount * (cnstDefHeadVarStruct.TextSize + 2 *
          fCellMargin);
    end
    else
      Result := FColWidth.Last
  end
  else if Index >= 0 then
    Result := FColWidth[Index]
  else
    Result := 0;
end;

function TsgDXFAcadTable.GetEntType: TsgCADEntities;
begin
  Result := ceACADTable;
end;

function TsgDXFAcadTable.GetFlags: Integer;
begin
  Result := FFlags;
end;

procedure TsgDXFAcadTable.Link(AConverter: TsgDXFConverter);
var
  R, C: Integer;
begin
  inherited Link(AConverter);
  if Assigned(Style) and (Style.ClassType = TsgLinkObject) then
    Style := TsgDXFAcadTableStyle(TsgLinkObject(Style)
      .GetObject(AConverter.Sections[csTableStyles]));
  for R := 0 to NumRows - 1 do
    for C := 0 to NumCols - 1 do
      Cell[C, R].Link(AConverter);
end;

procedure TsgDXFAcadTable.LoadedInternal(AConverter: TsgDXFConverter);
var
  I, R, C: Integer;
  vCell: TsgAcadTableCell;
  vAcadTableGenerator: TsgAcadTableGenerator;
begin
  FScale := cnstFPointSingle;
  FAngle := 0;
  // initialize SpanX and SpanY property of TsgAcadTableCell class
  R := 0;
  while R < NumRows do
  begin
    C := 0;
    while C < NumCols do
    begin
      vCell := Cell[C, R];
      if vCell.IsBaseCell then
      begin
        MergeCells(C, R, vCell.MergedWidth - 1, vCell.MergedHeight - 1);
        Inc(C, vCell.MergedWidth);
      end
      else
        Inc(C);
    end;
    Inc(R);
  end;

  R := 0;
  while R < NumRows do
  begin
    C := 0;
    while C < NumCols do
    begin
      vCell := Cell[C, R];
      for I := 0 to 5 do
        vCell.UpdateFlags(I);
      Inc(C);
    end;
    Inc(R);
  end;

  if not(AConverter.FStatus = stLoading) and IsBlockInternal then
    if not FLockGenerateBlock then
    begin
      vAcadTableGenerator := TsgAcadTableGenerator.Create(AConverter, Self);
      try
        Block := vAcadTableGenerator.GenerateBlock;
      finally
        vAcadTableGenerator.Free;
      end;
    end;
  inherited LoadedInternal(AConverter);
end;

procedure TsgDXFAcadTable.MergeCells(const ACol, ARow, ASpanX, ASpanY: Integer);
var
  vRange: TRect;
begin
  vRange := Rect(ACol, ARow, ACol + ASpanX, ARow + ASpanY);
  EnumRange(vRange, MergeCell, @vRange);
end;

function TsgDXFAcadTable.MergeCell(ACol, ARow: Integer;
  AParam: Pointer): Boolean;
var
  vRange: PRect;
  vCell: TsgAcadTableCell;
begin
  Result := True;
  vCell := Cell[ACol, ARow];
  vRange := PRect(AParam);
  vCell.IsBaseCell := (ACol = vRange^.Left) and (ARow = vRange^.Top);
  if vCell.IsBaseCell then
  begin
    vCell.MergedWidth := vRange^.Right - ACol + 1;
    vCell.MergedHeight := vRange^.Bottom - ARow + 1;
    vCell.SpanX := vCell.MergedWidth - 1;
    vCell.SpanY := vCell.MergedHeight - 1;
  end
  else
  begin
    vCell.MergedWidth := 1;
    vCell.MergedHeight := 1;
    vCell.SpanX := vRange^.Right - ACol;
    vCell.SpanY := vRange^.Bottom - ARow;
  end;
end;

procedure TsgDXFAcadTable.ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord);
  function _IsInternalTableBlockRecord(ABlockRecord: TsgDXFBlockRecord)
    : Boolean;
  begin
    if ABlockRecord <> nil then
      Result := AnsiPos(sInternalACADTable, TryLinkToName(ABlockRecord)) = 1
    else
      Result := True;
  end;

begin
  if not _IsInternalTableBlockRecord(ABlockRecord) then
    inherited ReferenceBlockRecord(ABlockRecord);
end;

function TsgDXFAcadTable.ReleaseBlock: TsgDXFBlock;
begin
  Result := Block;
  Block := nil;
end;

procedure TsgDXFAcadTable.Resize(const AColCount, ARowCount: Integer);
var
  I, vCount: Integer;
begin
  if ARowCount < NumRows then
    DeleteRows(ARowCount, NumRows - 1)
  else if ARowCount > NumRows then
  begin
    vCount := ARowCount - NumRows - 1;
    for I := 0 to vCount do
      AddRow;
  end;
  if AColCount < NumCols then
    DeleteCols(AColCount, NumCols - 1)
  else if AColCount > NumCols then
  begin
    vCount := AColCount - NumCols - 1;
    for I := 0 to vCount do
      AddCol;
  end;
end;

{ TsgDXFAcadTableStyle }

function TsgDXFAcadTableStyle.GetCellStyle(Index: TsgAcadTableCellType)
  : TsgAcadTableCellStyle;
begin
  Result := FCellStyle[Index];
end;

function TsgDXFAcadTableStyle.GetFlags: Integer;
begin
  Result := FFlags;
end;

procedure TsgDXFAcadTableStyle.Link(AConverter: TsgDXFConverter);
var
  I: TsgAcadTableCellType;
begin
  inherited Link(AConverter);
  for I := Low(TsgAcadTableCellType) to High(TsgAcadTableCellType) do
    CellStyle[I].Link(AConverter);
end;

procedure TsgDXFAcadTableStyle.LoadedInternal(AConverter: TsgDXFConverter);
var
  I: TsgAcadTableCellType;
begin
  inherited LoadedInternal(AConverter);
  for I := Low(TsgAcadTableCellType) to High(TsgAcadTableCellType) do
    if not Assigned(CellStyle[I].TextStyle) then
      CellStyle[I].TextStyle := AConverter.StyleByName(sStandardName);
end;

procedure TsgDXFAcadTableStyle.SetCellStyle(Index: TsgAcadTableCellType;
  const AValue: TsgAcadTableCellStyle);
begin
  FCellStyle[Index].Assign(AValue);
end;

procedure TsgDXFAcadTableStyle.SetDescription(const AValue: string);
begin
  FDescription := AValue;
end;

procedure TsgDXFAcadTableStyle.SetFlags(const Value: Integer);
begin
  FFlags := Value;
end;

procedure TsgDXFAcadTableStyle.SetFlowDirection(const AValue: Integer);
begin
  FFlowDirection := AValue;
end;

procedure TsgDXFAcadTableStyle.SetHeaderSuppressed(const AValue: Boolean);
begin
  FHeaderSuppressed := AValue;
end;

procedure TsgDXFAcadTableStyle.SetHorzCellMargin(const AValue: Double);
begin
  FHorzCellMargin := AValue;
end;

procedure TsgDXFAcadTableStyle.SetTitleSuppressed(const AValue: Boolean);
begin
  FTitleSuppressed := AValue;
end;

procedure TsgDXFAcadTableStyle.SetVertCellMargin(const AValue: Double);
begin
  FVertCellMargin := AValue;
end;

procedure TsgDXFAcadTableStyle.ClearReferences;
begin
  inherited ClearReferences;
end;

constructor TsgDXFAcadTableStyle.Create;
var
  I: TsgAcadTableCellType;
begin
  inherited Create;
  for I := Low(TsgAcadTableCellType) to High(TsgAcadTableCellType) do
    FCellStyle[I] := TsgAcadTableCellStyle.Create(Self, I);
  FHorzCellMargin := fCellMargin;
  FVertCellMargin := fCellMargin;
end;

procedure TsgDXFAcadTableStyle.FreeReferences;
var
  I: TsgAcadTableCellType;
begin
  inherited FreeReferences;
  for I := Low(TsgAcadTableCellType) to High(TsgAcadTableCellType) do
    FreeAndNil(FCellStyle[I]);
end;

procedure TsgDXFAcadTableStyle.AssignEntity(Source: TsgDXFEntity);
var
  I: TsgAcadTableCellType;
  vSource: TsgDXFAcadTableStyle;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFAcadTableStyle then
  begin
    vSource := TsgDXFAcadTableStyle(Source);
    FFlags := vSource.Flags;
    for I := Low(TsgAcadTableCellType) to High(TsgAcadTableCellType) do
      CellStyle[I] := vSource.CellStyle[I];
    FHeaderSuppressed := vSource.HeaderSuppressed;
    FDescription := vSource.Description;
    FFlowDirection := vSource.FlowDirection;
    FHorzCellMargin := vSource.HorzCellMargin;
    FTitleSuppressed := vSource.TitleSuppressed;
    FVertCellMargin := vSource.VertCellMargin;
  end;
end;

{ TsgAcadTableCellStyle }

procedure TsgAcadTableCellStyle.Assign(Source: TPersistent);
var
  I: Integer;
  vSource: TsgAcadTableCellStyle;
begin
  if Source is TsgAcadTableCellStyle then
  begin
    vSource := TsgAcadTableCellStyle(Source);
    FAcadTableStyle := vSource.AcadTableStyle;
    FBkColorOn := vSource.BkColorOn;
    for I := 0 to FBorderParams.Count - 1 do
      PsgCellBorderParam(FBorderParams[I])^ :=
        PsgCellBorderParam(vSource.FBorderParams[I])^;
    FCellAlignment := vSource.CellAlignment;
    FDataType := vSource.DataType;
    FFillColor := vSource.FillColor;
    FCellInitProps := vSource.FCellInitProps;
    TextStyle := vSource.TextStyle;
    FTextColor := vSource.TextColor;
    FTextHeight := vSource.TextHeight;
    FUnitType := vSource.UnitType;
  end
  else
    inherited Assign(Source);
end;

constructor TsgAcadTableCellStyle.Create(AAcadTableStyle: TsgDXFAcadTableStyle);
begin
  Create(AAcadTableStyle, cttData);
end;

constructor TsgAcadTableCellStyle.Create(AAcadTableStyle: TsgDXFAcadTableStyle;
  const ACellType: TsgAcadTableCellType);
var
  I: Integer;
  vCellBorderParam: PsgCellBorderParam;
begin
  FAcadTableStyle := AAcadTableStyle;
  FCellType := ACellType;
  FTextStyleItem := TsgTableItem.Create;
  FTextColor := MakeColorCAD(acIndexColor, clDXFByBlock);
  FFillColor := MakeColorCAD(acIndexColor, clDXFBlackWhite);
  FTextHeight := cnstDefHeadVarStruct.TextSize;
  FDataType := 0;
  FCellAlignment := 2;
  FUnitType := 0;
  FBkColorOn := False;
  FBorderParams := TList.Create;
  for I := 0 to 5 do
  begin
    New(vCellBorderParam);
    FBorderParams.Add(vCellBorderParam);
    vCellBorderParam^.Color := FTextColor;
    vCellBorderParam^.LineWeight := fLineWeightByBlock;
    vCellBorderParam^.Visible := True;
  end;
end;

destructor TsgAcadTableCellStyle.Destroy;
begin
  FreeRecordList(FBorderParams);
  FAcadTableStyle := nil;
  TextStyle := nil;
  FreeAndNil(FTextStyleItem);
  inherited Destroy;
end;

function TsgAcadTableCellStyle.GetBorderColor(Index: Integer): TsgColorCAD;
begin
  Result := PsgCellBorderParam(FBorderParams[Index])^.Color;
end;

function TsgAcadTableCellStyle.GetBorderCount: Integer;
begin
  Result := FBorderParams.Count;
end;

function TsgAcadTableCellStyle.GetBorderLineWeight(Index: Integer): Double;
begin
  Result := PsgCellBorderParam(FBorderParams[Index])^.LineWeight;
end;

function TsgAcadTableCellStyle.GetBorderVisible(Index: Integer): Boolean;
begin
  Result := PsgCellBorderParam(FBorderParams[Index])^.Visible;
end;

function TsgAcadTableCellStyle.GetTextStyle: TsgDXFStyle;
begin
  Result := TsgDXFStyle(FTextStyleItem.Item);
end;

function TsgAcadTableCellStyle.IsPropInit(const ACellProp: TsgCellProp)
  : Boolean;
begin
  Result := ACellProp in FCellInitProps;
end;

procedure TsgAcadTableCellStyle.Link(AConverter: TsgDXFConverter);
begin
  if Assigned(TextStyle) and (TextStyle.ClassType = TsgLinkObject) then
    TextStyle := TsgDXFStyle(TsgLinkObject(TextStyle)
      .GetObject(AConverter.Sections[csStyles]));
end;

procedure TsgAcadTableCellStyle.SetBkColorOn(const AValue: Boolean);
begin
  FBkColorOn := AValue;
end;

procedure TsgAcadTableCellStyle.SetBorderColor(Index: Integer;
  const AValue: TsgColorCAD);
begin
  PsgCellBorderParam(FBorderParams[Index])^.Color := AValue;
end;

procedure TsgAcadTableCellStyle.SetBorderLineWeight(Index: Integer;
  const AValue: Double);
begin
  PsgCellBorderParam(FBorderParams[Index])^.LineWeight := AValue;
end;

procedure TsgAcadTableCellStyle.SetBorderVisible(Index: Integer;
  const AValue: Boolean);
begin
  PsgCellBorderParam(FBorderParams[Index])^.Visible := AValue;
end;

procedure TsgAcadTableCellStyle.SetCellAlignment(const AValue: Integer);
begin
  FCellAlignment := AValue;
end;

procedure TsgAcadTableCellStyle.SetCellType(const AValue: TsgAcadTableCellType);
begin
  FCellType := AValue;
end;

procedure TsgAcadTableCellStyle.SetDataType(const AValue: Integer);
begin
  FDataType := AValue;
end;

procedure TsgAcadTableCellStyle.SetFillColor(const AValue: TsgColorCAD);
begin
  FFillColor := AValue;
end;

procedure TsgAcadTableCellStyle.SetPropInit(const ACellProp: TsgCellProp;
  const AInclude: Boolean);
begin
  if AInclude then
    Include(FCellInitProps, ACellProp)
  else
    Exclude(FCellInitProps, ACellProp);
end;

procedure TsgAcadTableCellStyle.SetTextColor(const AValue: TsgColorCAD);
begin
  FTextColor := AValue;
end;

procedure TsgAcadTableCellStyle.SetTextHeight(const AValue: Double);
begin
  FTextHeight := AValue;
end;

procedure TsgAcadTableCellStyle.SetTextStyle(const AValue: TsgDXFStyle);
begin
  FTextStyleItem.Item := AValue;
end;

procedure TsgAcadTableCellStyle.SetUnitType(const AValue: Integer);
begin
  FUnitType := AValue;
end;

{ TsgDXFProxy }

procedure TsgDXFProxy.Clear(const ADoFree: Boolean);
begin
  inherited Clear(ADoFree);
  ClearEntCollection(FEntities, ADoFree);
end;

constructor TsgDXFProxy.Create;
begin
  inherited Create;
  FEntities := TListNotify(TListNotify.CreateList(ListNotify));
end;

procedure TsgDXFProxy.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FEntities);
end;

function TsgDXFProxy.GetBox: TFRect;
begin
  Result := FBox;
end;

function TsgDXFProxy.GetCount: Integer;
begin
  Result := FEntities.Count;
end;

function TsgDXFProxy.GetEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := TsgDXFEntity(FEntities[AIndex]);
end;

function TsgDXFProxy.GetEntType: TsgCADEntities;
begin
  Result := ceProxy;
end;

function TsgDXFProxy.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  Result := True;
  FEntities.Insert(AIndex, AEntity);
end;

procedure TsgDXFProxy.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
var
  I: Integer;
begin
  if Assigned(Proc) then
    Proc(Self);
  try
    for I := 0 to Count - 1 do
      Entities[I].Invoke(AConverter, Proc, FinishProc);
  finally
    if Assigned(FinishProc) then
      FinishProc(Self);
  end;
end;

function TsgDXFProxy.GroupExists: Boolean;
begin
  Result := True;
end;

procedure TsgDXFProxy.LoadedInternal(AConverter: TsgDXFConverter);
var
  I: Integer;
begin
  inherited LoadedInternal(AConverter);
  FBox := BadRect;
  for I := 0 to Count - 1 do // FBox is union of all entities
    if Entities[I].Visibility = True then
      UnionFRect(FBox, Entities[I].Box);
end;

procedure TsgDXFProxy.SetEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity);
begin
  FEntities[AIndex] := AEntity;
end;

{ TsgFlatEntity }

function TsgFlatEntity.CanDraw: Boolean;
begin
  Result := True;
end;

function TsgFlatEntity.CanHaveHandle: Boolean;
begin
  Result := False;
end;

procedure TsgFlatEntity.ClearReferences;
begin
  inherited ClearReferences;
  FCounts.Clear;
  FPoints.Clear;
end;

procedure TsgFlatEntity.CopyProperty(const AEntity: TsgDXFEntity);
begin
  ColorCAD := AEntity.ColorCAD;
  LineWeight := AEntity.LineWeight;
  Layer := AEntity.Layer;
end;

constructor TsgFlatEntity.Create;
begin
  inherited Create;
  FBox := BadRect;
  FCounts := TsgIntegerList.Create;
  FPoints := TsgBaseListClass(GetPointsClass).Create;
end;

function TsgFlatEntity.GroupFill(AConverter: TsgDXFConverter): Boolean;
begin
  Result := False;
end;

procedure TsgFlatEntity.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FCounts);
  FreeAndNil(FPoints);
end;

function TsgFlatEntity.Accepts(const AEntity: TsgDXFEntity): Boolean;
begin
  Result := (Color = AEntity.Color);
end;

procedure TsgFlatEntity.AddPolyline(P: TsgCADBasePolyline);
var
  vBox: TFRect;
begin
  if PCount = 0 then
    CopyProperty(P);
  begin
    ColorCAD := P.ColorCAD;
    LineWeight := P.LineWeight;
    Layer := P.Layer;
  end;
  vBox := P.Box;
  AddPoints(P.PolyPoints, P.Closed, @vBox);
end;

procedure TsgFlatEntity.AddPolygon(P: TsgCADPolyPolygon);
var
  C, I, J: Integer;
  vPoint2D: TF2DPoint;
  L: TF2DPointList;
begin
  if FCounts.Count = 0 then
    ColorCAD := P.ColorCAD; // CopyProperty(P);
  C := 0;
  for I := 0 to P.Boundaries.Count - 1 do
  begin
    L := TF2DPointList(P.Boundaries[I]);
    if L.Count > 0 then
      Inc(C);
  end;
  FCounts.Add(C);
  C := 0;
  UnionFRect(FBox, P.Box);
  for I := 0 to P.Boundaries.Count - 1 do
  begin
    L := TF2DPointList(P.Boundaries[I]);
    if L.Count = 0 then
      Continue;
    FCounts.Add(L.Count);
    for J := 0 to L.Count - 1 do
    begin
      vPoint2D := L[J];
      AddPoint(vPoint2D.X, vPoint2D.Y);
      Inc(C);
    end;
  end;
  FCounts.Add(C);
end;

procedure TsgFlatEntity.AddPoints(const APoints: TFPointList;
  const AClosed: Boolean; const ABox: PFRect = nil);
var
  C, I: Integer;
  vExpandBox: Boolean;
begin
  if APoints.Count < 1 then
    Exit;
  vExpandBox := (ABox = nil) or IsBadRect(ABox^);
  if not vExpandBox then
    UnionFRect(FBox, ABox^);
  C := APoints.Count;
  for I := 0 to C - 1 do
  begin
    AddFPoint(APoints[I]);
    if vExpandBox then
      ExpandFRect(FBox, APoints[I]);
  end;
  if AClosed then
  begin
    AddFPoint(APoints[0]);
    Inc(C);
  end;
  FCounts.Add(C);
end;

procedure TsgFlatEntity.AddLine(const ALine: TsgDXFLine);
begin
  if PCount = 0 then
    CopyProperty(ALine);
  UnionFRect(FBox, ALine.Box);
  AddFPoint(ALine.Point);
  AddFPoint(ALine.Point1);
  FCounts.Add(2);
end;

function TsgFlatEntity.Add(const AEntity: TsgDXFEntity): Boolean;
begin
  Result := False;
  if AEntity is TsgCADBasePolyline then
  begin
    Result := True;
    AddPolyline(TsgCADBasePolyline(AEntity));
  end
  else
  begin
    if AEntity is TsgCADPolyPolygon then
    begin
      Result := True;
      AddPolygon(TsgCADPolyPolygon(AEntity));
    end
    else
    begin
      if AEntity is TsgDXFLine then
      begin
        Result := True;
        AddLine(TsgDXFLine(AEntity));
      end;
    end;
  end;
end;

function TsgFlatEntity.AddSegment(const APoints: TFPointList;
  const AMerge: Boolean): Boolean;
var
  I: Integer;
begin
  Result := AMerge and (APoints.Count > 0) and (PCount > 0) and
    IsEqualFPoints(XY[PCount - 1], APoints.First);
  if Result then
  begin
    for I := 1 to APoints.Count - 1 do
      AddSegmentPoint(APoints[I], False);
  end
  else
    AddPoints(APoints, False, nil);
end;

function TsgFlatEntity.AddSegmentPoint(const APoint: TFPoint;
  const ACreateNewSegment: Boolean): Integer;
begin
  if ACreateNewSegment or (FCounts.Count = 0) then
    FCounts.Add(0);
  FCounts.Last := FCounts.Last + 1;
  AddFPoint(APoint);
  ExpandFRect(FBox, APoint);
  Result := FCounts.Last;
end;

procedure TsgFlatEntity.AddFPoint(const APoint: TFPoint);
begin
  AddPoint(APoint.X, APoint.Y, APoint.Z);
end;

procedure TsgFlatEntity.AssignEntity(Source: TsgDXFEntity);
var
  vFlatEntity: TsgFlatEntity absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgFlatEntity then
  begin
    FBox := vFlatEntity.FBox;
    FCounts.Assign(vFlatEntity.FCounts);
    if FPoints.ClassType = vFlatEntity.FPoints.ClassType then
      FPoints.Assign(vFlatEntity.FPoints);
  end;
end;

function TsgFlatEntity.GetBox: TFRect;
begin
  Result := FBox;
end;

function TsgFlatEntity.GetPointsSignleList: TsgSingleList;
begin
  Result := nil;
end;

function TsgFlatEntity.GetXYLast: TFPoint;
begin
  if PCount > 0 then
    Result := XY[PCount - 1]
  else
    Result := cnstBadPoint;
end;

function TsgFlatEntity.PCount: Integer;
begin
  Result := 0;
end;

function TsgFlatEntity.GroupHasAddedEntities: Boolean;
begin
  Result := True;
end;

procedure TsgFlatEntity.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
  if Layer = nil then
    Layer := AConverter.LayerByName('0');
end;

function TsgFlatEntity.GroupExists: Boolean;
begin
  Result := True;
end;

procedure TsgFlatEntity.SetBox(const ABox: TFRect);
begin
  FBox := ABox;
end;

procedure TsgFlatEntity.SetHandle(const Value: UInt64);
begin
{$IFDEF SG_MODULE_LOG}
  inherited SetHandle(Value);
{$ENDIF}
end;

{ TsgFlatPoly }

function TsgFlatPoly.Accepts(const AEntity: TsgDXFEntity): Boolean;
var
  P: TsgCADBasePolyline absolute AEntity;
begin
  Result := inherited Accepts(AEntity) and (AEntity is TsgCADBasePolyline) and
    (PCount + P.PolyPoints.Count < $4000);
  if Result and (PCount > 0) then
    Result := (FLineWeight = P.LineWeight);
end;

function TsgFlatPoly.GetEntType: TsgCADEntities;
begin
  Result := ceFlatPoly;
end;

{ TsgFlatHatch }

function TsgFlatHatch.Accepts(const AEntity: TsgDXFEntity): Boolean;
var
  P: TsgCADPolyPolygon absolute AEntity;
begin
  Result := inherited Accepts(AEntity) and (AEntity is TsgCADPolyPolygon) and
    (Counts.Count + P.Boundaries.Count <= 4096);
end;

function TsgFlatHatch.GroupFill(AConverter: TsgDXFConverter = nil): Boolean;
var
  I, J, K, vCount, vSubCount, vIndex: Integer;
  vHatch: TsgCADMPolygon;
  vBoundary: Tsg2DBoundaryList;
  procedure AddCurve(Boundary: Tsg2DBoundaryList;
    StartPoint, EntPoint: TF2DPoint);
  var
    vCurve: Tsg2DLine;
  begin
    vCurve := Tsg2DLine.Create;
    vCurve.SetStartPoint(StartPoint);
    vCurve.SetEndPoint(EntPoint);
    Boundary.Add(vCurve);
  end;

begin
  vIndex := 0;
  I := 0;
  while I < Counts.Count do
  begin
    vCount := Self.Counts[I];
    Inc(I);
    if vCount = 0 then
      Break;
    vHatch := TsgCADMPolygon.Create;
    for J := 0 to vCount - 1 do
    begin
      vBoundary := vHatch.AddBoundaryList(1);
      vSubCount := Self.Counts[I];
      Inc(I);
      for K := vIndex + 1 to (vIndex + vSubCount - 1) do
        AddCurve(vBoundary, MakeF2DPointFrom3D(Self.XY[K - 1]),
          MakeF2DPointFrom3D(Self.XY[K]));
      AddCurve(vBoundary, MakeF2DPointFrom3D(Self.XY[vIndex + vSubCount - 1]),
        // To close
        MakeF2DPointFrom3D(Self.XY[vIndex]));
      Inc(vIndex, vSubCount);
    end;
    Inc(I);
    vHatch.AssignEntity(Self);
    vHatch.Extrusion := cnstZOrtAxis;
    vHatch.Elevation := cnstFPointZero;
    vHatch.HatchName := sSOLID;
    TsgCADMPolygon(vHatch).FillColor := ColorCAD;
    vHatch.SolidFill := True;
    vHatch.HatchStyle := hsSolid;
    vHatch.FillStyle := fsSolid;
    vHatch.Loaded(AConverter);
    Group.AddEntity(vHatch);
  end;
  Result := Group.Count > 0;
end;

function TsgFlatHatch.GetEntType: TsgCADEntities;
begin
  Result := ceFlatHatch;
end;

{ TsgDXFOle2Frame }

constructor TsgDXFOle2Frame.Create;
begin
  inherited Create;
  FTileModeDescriptor := 0;
  // Object resides in model space. On export header need xor 1
  FAspect := DVASPECT_CONTENT;
  FOLEObjectType := 2;
end;

procedure TsgDXFOle2Frame.AssignEntity(Source: TsgDXFEntity);
var
  vOle2Frame: TsgDXFOle2Frame absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFOle2Frame then
  begin
    FAspect := vOle2Frame.FAspect;
    FBinaryData := vOle2Frame.FBinaryData;
    DestroyOleObject;
    FOLEObjectType := vOle2Frame.FOLEObjectType;
    FPoint1 := vOle2Frame.FPoint1;
  end;
end;

procedure TsgDXFOle2Frame.DestroyOleObject;
begin
  FOleObject := nil;
  FStorage := nil;
  FLockBytes := nil;
end;

function TsgDXFOle2Frame.GetBox: TFRect;
begin
  Result := cnstBadRect;
  ExpandFRect(Result, Point);
  ExpandFRect(Result, Point1);
end;

procedure TsgDXFOle2Frame.LoadedInternal(AConverter: TsgDXFConverter);
var
  vSize: Integer;
  vDataHandle: HGlobal;
  vBuffer: Pointer;
begin
  inherited LoadedInternal(AConverter);
  DestroyOleObject;
  vSize := Length(FBinaryData);
  vDataHandle := GlobalAlloc(GMEM_MOVEABLE, vSize);
  if vDataHandle <> 0 then
    try
      vBuffer := GlobalLock(vDataHandle);
      Move(FBinaryData[1], vBuffer^, vSize);
      GlobalUnlock(vDataHandle);
      if Succeeded(CreateILockBytesOnHGlobal(vDataHandle, True, FLockBytes))
      then
      begin
        vDataHandle := 0;
        if Succeeded(StgOpenStorageOnILockBytes(FLockBytes, nil,
          STGM_READWRITE or STGM_SHARE_EXCLUSIVE, nil, 0, FStorage)) then
        begin
          if not Succeeded(OleLoad(FStorage, IOleObject, nil, FOleObject)) then
            DestroyOleObject;
        end
        else
          DestroyOleObject;
      end;
    except
      if vDataHandle <> 0 then
        GlobalFree(vDataHandle);
    end;
end;

function TsgDXFOle2Frame.GetEntType: TsgCADEntities;
begin
  Result := ceOle2Frame;
end;

function TsgDXFOle2Frame.GetFileName: string;
var
  vOleLonk: IOleLink;
  vTmpFileName: PWideChar;
begin
  Result := '';
  if IsLink and (FOleObject.QueryInterface(IOleLink, vOleLonk) = S_OK) then
    try
      if vOleLonk.GetSourceDisplayName(vTmpFileName) = S_OK then
        try
          Result := WideCharToString(vTmpFileName);
        finally
          CoTaskMemFree(vTmpFileName);
        end;
    finally
      vOleLonk := nil;
    end;
end;

function TsgDXFOle2Frame.GetIsLink: Boolean;
var
  vStatus: {$IFDEF SGFPC}DWORD{$ELSE}Integer{$ENDIF};
begin
  Result := False;
  if FOleObject <> nil then
    if FOleObject.GetMiscStatus(DVASPECT_CONTENT, vStatus) = S_OK then
      Result := vStatus and OLEMISC_ISLINKOBJECT <> 0;
end;

function TsgDXFOle2Frame.GetPoint1: TFPoint;
begin
  Result := FPoint1;
end;

function TsgDXFOle2Frame.GetPosition: TFPoint;
begin
  Result := Point;
end;

function TsgDXFOle2Frame.GetSize: TFPoint;
begin
  Result := AbsFPoint(SubFPoint(Point1, Point));
end;

procedure TsgDXFOle2Frame.SetPoint1(const Value: TFPoint);
begin
  FPoint1 := Value;
end;

procedure TsgDXFOle2Frame.SetPosition(const APoint: TFPoint);
var
  vDelta: TFPoint;
begin
  vDelta := SubFPoint(APoint, Point);
  Point := APoint;
  Point1 := AddFPoint(Point1, vDelta);
end;

procedure TsgDXFOle2Frame.SetSize(const APoint: TFPoint);
var
  vOldSize, vNewSize: TFPoint;
begin
  vOldSize := SubFPoint(Point1, Point);
  vNewSize := MultiplyFPoint(AbsFPoint(APoint), SignFPoint(vOldSize));
  Point1 := AddFPoint(Point, vNewSize);
end;

procedure TsgDXFOle2Frame.ClearReferences;
begin
  inherited ClearReferences;
  DestroyOleObject;
end;

procedure TsgDXFOle2Frame.ConvertOleToBitmap(const AWidth, AHeight: Double;
  ADrawingRect: TRect; const ABitmap: TBitmap);
var
  vRect: TRect;
  vSize: TPoint;
  vRatio: Double;
begin
  if GetOleExtents(FOleObject, FAspect, vSize) and
    ((vSize.X * vSize.Y) < cnstMaxImgSizeSqrt) then
  begin
    vRect := Rect(0, 0, vSize.X, vSize.Y);
  end
  else
  begin
    vRect := Rect(0, 0, ADrawingRect.Right - ADrawingRect.Left,
      ADrawingRect.Bottom - ADrawingRect.Top);
    if (AWidth * AHeight) > cnstMaxImgSizeSqrt then
    begin
      if AHeight > AWidth then
      begin
        vRatio := AWidth / AHeight;
        vRect := Rect(0, 0, Floor(cnstMaxImgSize * vRatio), cnstMaxImgSize);
      end
      else
      begin
        vRatio := AHeight / AWidth;
        vRect := Rect(0, 0, cnstMaxImgSize, Floor(cnstMaxImgSize * vRatio));
      end;
    end;
  end;
  ABitmap.PixelFormat := pf24bit;
  ABitmap.Width := vRect.Right;
  ABitmap.Height := vRect.Bottom;
  ABitmap.Canvas.Brush.Style := bsSolid;
  ABitmap.Canvas.Brush.Color := clWindow;
  ABitmap.Canvas.FillRect(vRect);
  OleDraw(FOleObject, FAspect, ABitmap.Canvas.Handle, vRect);
end;

{ TsgCADGradientPolygon }

constructor TsgCADGradientPolygon.Create;
begin
  inherited Create;
  FGradientColor[0] := MakeColorCAD(acRGBColor, ConvertRGBtoColor(0, 0, 255));
  FGradientColor[1] := MakeColorCAD(acRGBColor,
    ConvertRGBtoColor(255, 255, 255));
  FGradientUseCenter := True;
end;

procedure TsgCADGradientPolygon.AssignEntity(Source: TsgDXFEntity);
var
  vGradientPolygon: TsgCADGradientPolygon absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgCADGradientPolygon then
  begin
    FGradientColor := vGradientPolygon.FGradientColor;
    FType := vGradientPolygon.FType;
    FGradientAngle := vGradientPolygon.FGradientAngle;
    FGradientUseCenter := vGradientPolygon.FGradientUseCenter;
  end;
end;

function TsgCADGradientPolygon.GetEntType: TsgCADEntities;
begin
  Result := ceGradientPolygon;
end;

function TsgCADGradientPolygon.GetHatchName: string;
begin
  if FType = gtNone then
    Result := inherited GetHatchName
  else
    Result := 'GRADIENT';
end;

function TsgCADGradientPolygon.GetGradientAngle: TsgFloat;
begin
  Result := FGradientAngle;
end;

function TsgCADGradientPolygon.GetGradientColor(const AIndex: Byte): TColor;
begin
  Result := ConvertColorCADToRGB(GetGradientColorCAD(AIndex));
end;

function TsgCADGradientPolygon.GetGradientColorCAD(const AIndex: Byte)
  : TsgColorCAD;
begin
  case AIndex of
    0, 1:
      Result := FGradientColor[AIndex];
  else
    Result := MakeColorCAD(acIndexColor, clDXFBlackWhite);
  end;
end;

function TsgCADGradientPolygon.GetGradientName: string;
begin
  case FType of
    gtCurved:
      Result := cnstGradientName[0];
    gtCylinder:
      Result := cnstGradientName[1];
    gtHemiSpherical:
      Result := cnstGradientName[2];
    gtLinear:
      Result := cnstGradientName[3];
    gtSpherical:
      Result := cnstGradientName[4];
    gtInvCurved:
      Result := cnstGradientName[5];
    gtInvCylinder:
      Result := cnstGradientName[6];
    gtInvHemiSpherical:
      Result := cnstGradientName[7];
    gtInvSpherical:
      Result := cnstGradientName[8];
    gtOther:
      Result := 'UNKNOWN';
  else
    Result := '';
  end;
end;

procedure TsgCADGradientPolygon.SetGradientAngle(const Value: TsgFloat);
var
  vValue: Double;
begin
  if sgModAngle(Value, vValue) then
    FGradientAngle := vValue;
end;

procedure TsgCADGradientPolygon.SetGradientColorCAD(const AIndex: Byte;
  const Value: TsgColorCAD);
begin
  case AIndex of
    0, 1:
      FGradientColor[AIndex] := Value;
  else
    // None
  end;
end;

procedure TsgCADGradientPolygon.SetGradientName(const AName: string);
var
  I, vLen: Integer;
  vName: string;
begin
  vLen := Length(AName);
  while (vLen > 0) and (AName[vLen] = #0) do
    Dec(vLen);
  if vLen > 0 then
  begin
    vName := UpperCase(Copy(AName, 1, vLen));
    I := 0;
    while (I < 9) and (vName <> cnstGradientName[I]) do
      Inc(I);
    case I of
      0:
        FType := gtCurved;
      1:
        FType := gtCylinder;
      2:
        FType := gtHemiSpherical;
      3:
        FType := gtLinear;
      4:
        FType := gtSpherical;
      5:
        FType := gtInvCurved;
      6:
        FType := gtInvCylinder;
      7:
        FType := gtInvHemiSpherical;
      8:
        FType := gtInvSpherical;
    else
      FType := gtOther;
    end;
  end
  else
    FType := gtNone;
end;

{ TsgDXFObjectEntity }

procedure TsgDXFObjectEntity.GroupClear;
var
  I: Integer;
begin
  if not GroupExists then
    Exit;
  if Assigned(Group) then
  begin
    if GroupHasAddedEntities then
      for I := 0 to Group.Count - 1 do
        Group[I].Free;
    Group.FEntities.Clear;
    Group.Clear(False);
  end;
  Group.Free;
  FGroup := nil;
end;

function TsgDXFObjectEntity.CanHaveHandle: Boolean;
begin
  Result := True;
end;

procedure TsgDXFObjectEntity.ClearReferences;
begin
  inherited ClearReferences;
  FLayerItem.Item := nil;
end;

constructor TsgDXFObjectEntity.Create;
begin
  inherited Create;
  FLayerItem := TsgTableItem.Create;
  FHandle := cnstBadHandle;
  LineCap := PS_ENDCAP_ROUND;
  LineJoin := PS_JOIN_ROUND;
  FGroup := nil;
end;

procedure TsgDXFObjectEntity.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FLayerItem);
end;

function TsgDXFObjectEntity.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlLayerName:
      begin
        if Assigned(Converter) then
          Layer := Converter.GetLayerByNode(ANode);
        if not Assigned(Layer) then
        begin
          DoErrorXMLNode(AResult.Errors, False, ANode, xmlLayerName);
        end;
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFObjectEntity.GroupCreate(AConverter
  : TsgDXFConverter = nil): Boolean;
begin
  Result := GroupExists;
  if not Result then
    Exit
  else
  begin
    GroupClear;
    FGroup := TsgDXFGroup.Create;
    Result := GroupFill(AConverter);
  end;
end;

function TsgDXFObjectEntity.GroupFill(AConverter: TsgDXFConverter): Boolean;
var
  I: Integer;
  vEntity: TsgDXFEntity;
begin
  if Assigned(Group) then
  begin
    if Group.Count = 0 then
    begin
      for I := 0 to Count - 1 do
      begin
        vEntity := Self[I];
        if (vEntity.EntType <> ceEntity) and // skip internal entity in export
          ((vEntity.Handle <> cnstBadHandle) or (not vEntity.CanHaveHandle))
        then
          Group.AddEntity(vEntity);
      end;
      Result := Group.Count > 0;
    end
    else
      Result := True;
  end
  else
    Result := False;
end;

procedure TsgDXFObjectEntity.AssignEntity(Source: TsgDXFEntity);
var
  vObjectEntity: TsgDXFObjectEntity absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFObjectEntity then
  begin
    FInternalFlags := vObjectEntity.InternalFlags;
    Layer := vObjectEntity.Layer; // use ptoperty for calc layer refcount
    FFlag := vObjectEntity.FFlag;
    FPenStyle := vObjectEntity.FPenStyle;
{$IFDEF SG_USEDXFSRC}
    FSrcEnd := vObjectEntity.FSrcEnd;
    FSrcStart := vObjectEntity.FSrcStart;
{$ENDIF}
  end;
end;

function TsgDXFObjectEntity.GetVisibility: Boolean;
begin
  Result := (FFlag and 128) = 0;
end;

procedure TsgDXFObjectEntity.Link(AConverter: TsgDXFConverter);
var
  vLayerTemp: TsgDXFLayer;
begin
  inherited Link(AConverter);
  SetConverter(AConverter);
  if Assigned(Layer) and (Layer.ClassType = TsgLinkObject) then
  begin
    vLayerTemp := TsgDXFLayer(TsgLinkObject(Layer)
      .GetObject(AConverter.Sections[csLayers]));
    if not Assigned(vLayerTemp) then
    begin
      if (TsgLinkObject(Layer).LinkType = lodtName) then
        Layer := AConverter.LayerByName(TsgLinkObject(Layer).Name)
      else
        Layer := TsgDXFLayer(AConverter.Sections[csLayers].FindEntByName('0'));
    end
    else
      Layer := vLayerTemp;
  end;
end;

procedure TsgDXFObjectEntity.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
end;

procedure TsgDXFObjectEntity.SetVisibility(const Value: Boolean);
begin
  FFlag := (FFlag and 127) or (Byte(not Value) shl 7);
end;

function TsgDXFObjectEntity.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  if IsXMLHelp(AMode) then
    ANode.AddAttribNV(cnstXMLNames[xmlLayerName].Name)
  else if Assigned(Layer) and (IsFullProps(AMode) or (Layer.Name <> '0')) then
    ANode.AddAttribNV(cnstXMLNames[xmlLayerName].Name).ValueAsStr := Layer.Name;
end;

function TsgDXFObjectEntity.GetLayer: TsgDXFLayer;
begin
  Result := TsgDXFLayer(FLayerItem.Item);
end;

procedure TsgDXFObjectEntity.SetLayer(const Value: TsgDXFLayer);
begin
  FLayerItem.Item := Value;
end;

function TsgDXFObjectEntity.GetConverter: TsgDXFConverter;
begin
  if Assigned(FConverter) then
    Result := FConverter
  else
    Result := inherited GetConverter;
end;

function TsgDXFObjectEntity.GetFlags: Integer;
begin
  Result := FFlag;
end;

function TsgDXFObjectEntity.GroupGet: TsgDXFGroup;
begin
  Result := FGroup;
end;

function TsgDXFObjectEntity.GetHandle: UInt64;
begin
  Result := FHandle;
end;

function TsgDXFObjectEntity.GetInternalFlags: Byte;
begin
  Result := FInternalFlags;
end;

procedure TsgDXFObjectEntity.SetConverter(const AConverter: TsgDXFConverter);
begin
  if FConverter <> AConverter then
  begin
    if Assigned(FConverter) then
    begin
{$IFDEF CONV_REFCOUNT}
      Dec(FConverter.FRefCount);
      FConverter.FRefEnts.Remove(Self);
{$ENDIF}
      FConverter.RemoveFromEntitiesWithGeneratedHandles(Self);
    end;
    FConverter := AConverter;
    if Assigned(FConverter) then
    begin
{$IFDEF CONV_REFCOUNT}
      Inc(FConverter.FRefCount);
      FConverter.FRefEnts.Add(Self);
{$ENDIF}
      if CanHaveHandle and (FHandle = cnstBadHandle) then
        FConverter.AddEntitiesWithGeneratedHandles(Self);
    end;
  end;
end;

procedure TsgDXFObjectEntity.SetFlags(const Value: Integer);
begin
  FFlag := Value;
end;

procedure TsgDXFObjectEntity.SetHandle(const Value: UInt64);
begin
{$IFDEF SG_MODULE_LOG}
  inherited SetHandle(Value);
{$ENDIF}
  // if FHandle <> Value then
  // begin
  // if GetOwner() <> nil then
  // GetOwner().DeleteHandleItem(Self);
  FHandle := Value;
  // if GetOwner() <> nil then
  // GetOwner().AddHandleItem(Self);
  // end;
end;

procedure TsgDXFObjectEntity.SetInternalFlags(const Value: Byte);
begin
  FInternalFlags := Value;
end;

function TsgDXFObjectEntity.GetLineCap: Word;
begin
  Result := FPenStyle and PS_ENDCAP_MASK;
end;

function TsgDXFObjectEntity.GetLineJoin: Word;
begin
  Result := FPenStyle and PS_JOIN_MASK;
end;

function TsgDXFObjectEntity.GetLineWeightScaled: Boolean;
begin
  Result := (FFlag and 16) <> 0;
end;

procedure TsgDXFObjectEntity.SetLineCap(const Value: Word);
begin
  FPenStyle := (FPenStyle and (not PS_ENDCAP_MASK)) or
    (Value and PS_ENDCAP_MASK);
end;

procedure TsgDXFObjectEntity.SetLineJoin(const Value: Word);
begin
  FPenStyle := (FPenStyle and (not PS_JOIN_MASK)) or (Value and PS_JOIN_MASK);
end;

procedure TsgDXFObjectEntity.SetLineWeightScaled(Value: Boolean);
begin
  FFlag := (FFlag and 239) or (Integer(Value) shl 4);
end;

procedure TsgDXFObjectEntity.SetOwner(const Value: TsgDXFEntity);
var
  vConv: TsgDXFConverter;
begin
  if Assigned(Value) then
    vConv := Value.Converter
  else
    vConv := nil;
  inherited SetOwner(Value);
  SetConverter(vConv);
end;

{$IFDEF SG_USEDXFSRC}

function TsgDXFObjectEntity.GetSrcEnd: PAnsiChar;
begin
  Result := FSrcEnd;
end;

function TsgDXFObjectEntity.GetSrcStart: PAnsiChar;
begin
  Result := FSrcStart;
end;

procedure TsgDXFObjectEntity.SetSrcEnd(const Value: PAnsiChar);
begin
  FSrcEnd := Value;
end;

procedure TsgDXFObjectEntity.SetSrcStart(const Value: PAnsiChar);
begin
  FSrcStart := Value;
end;
{$ENDIF}
{ TsgDXFObjectEntityColor }

function TsgDXFObjectEntityColor.GetColorCAD: TsgColorCAD;
begin
  Result := FColor;
end;

procedure TsgDXFObjectEntityColor.SetColorCAD(const Value: TsgColorCAD);
begin
  FColor := Value;
end;

function TsgDXFObjectEntityColor.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  if IsFullPropsOrXMLHelp(AMode) or
    (not IsEqualColorCAD(FColor, cnstColorCADByLayer)) then
    ANode.AddAttribNV(cnstXMLNames[xmlColor].Name).ValueData.ValueAsColorCAD
      := FColor;
end;

constructor TsgDXFObjectEntityColor.Create;
begin
  inherited Create;
  FColor := cnstDefHeadVarStruct.CEColor;
end;

function TsgDXFObjectEntityColor.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlColor:
      FColor := ANode.ValueData.ValueAsColorCAD;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure TsgDXFObjectEntityColor.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFObjectEntityColor then
    FColor := TsgDXFObjectEntityColor(Source).FColor;
end;

{ TsgSVGInsert }

procedure TsgSVGInsert.AssignEntity(Source: TsgDXFEntity);
var
  vInsert: TsgSVGInsert absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgSVGInsert then
  begin
    if FPrevMatrix <> nil then
    begin
      Dispose(FPrevMatrix);
      FPrevMatrix := nil;
    end;
    if vInsert.FPrevMatrix <> nil then
    begin
      New(FPrevMatrix);
      FPrevMatrix^ := vInsert.FPrevMatrix^;
    end;
  end;
end;

procedure TsgSVGInsert.FreeReferences;
begin
  inherited FreeReferences;
  DisposeAndNil(FPrevMatrix);
end;

function TsgSVGInsert.GetInitMatrix: TFMatrix;
begin
  if FPrevMatrix <> nil then
    Result := FPrevMatrix^
  else
    Result := cnstIdentityMat;
end;

procedure TsgSVGInsert.InitializeMatrix;
begin
  FMatrix := GetInitMatrix;
end;

procedure TsgSVGInsert.SetInitMatrix(const AMatrix: TFMatrix);
begin
  if not CompareMem(@AMatrix, @cnstIdentityMat, SizeOf(AMatrix)) then
  begin
    if FPrevMatrix = nil then
      New(FPrevMatrix);
    FPrevMatrix^ := AMatrix;
  end;
end;

{ TsgSVGMText }

procedure TsgSVGMText.CopyItems(const ASource: TsgDXFEntity);
var
  vBlockName: string;
  vMText: TsgSVGMText absolute ASource;
  vSrc, vDst: TsgDXFEntity;
  I: Integer;
begin
  inherited CopyItems(ASource);
  if (ASource is TsgSVGMText) and (vMText.Block <> nil) then
  begin
    vBlockName := Block.Name;
    Block.Clear;
    Block.AssignEntity(vMText.Block);
    Block.Name := vBlockName;
    for I := 0 to vMText.Block.Count - 1 do
    begin
      vSrc := vMText.Block[I];
      vDst := TsgDXFEntityClass(vSrc.ClassType).Create;
      vDst.AssignEntity(vSrc);
      Block.AddEntity(vDst);
    end;
    DelayedLoadAttribs := Block.Count > 0;
  end;
end;

constructor TsgSVGMText.Create;
begin
  inherited Create;
  Block := TsgDXFBlock.Create;
  Block.Name := 'SVGMText_' + IntToHex(TsgNativeUInt(Block), 0);
  Point := cnstFPointZero;
end;

procedure TsgSVGMText.DoDelayedLoad(AConverter: TsgDXFConverter);
var
  I: Integer;
begin
  for I := 0 to Block.Count - 1 do
    AConverter.Loads(Block.Entities[I]);
end;

procedure TsgSVGMText.ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord);
begin
  // do nothing, SVGMText must use only self created block
end;

{ TsgDXFTolerance }

procedure TsgDXFTolerance.AssignEntity(Source: TsgDXFEntity);
var
  vTolerance: TsgDXFTolerance absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFTolerance then
  begin
    FDimlineColor := vTolerance.FDimlineColor;
    FDimScaleOverall := vTolerance.FDimScaleOverall;
    FDimStyleItem.Item := vTolerance.FDimStyleItem.Item;
    if vTolerance.FGAP = nil then
      DisposeAndNil(FGAP)
    else
    begin
      if FGAP = nil then
        New(FGAP);
      FGAP^ := vTolerance.FGAP^;
    end;
  end;
end;

function TsgDXFTolerance.BeginExtData(const AData: TsgCADExtendedData): Boolean;
begin
  AData.AddString(String_1001, sACADXDataAppName);
  AData.AddString(String_1000, cnstDStyle);
  AData.AddString(String_1002, '{');
  Result := True;
end;

procedure TsgDXFTolerance.ClearReferences;
begin
  inherited ClearReferences;
  FDimStyleItem.Item := nil;
end;

constructor TsgDXFTolerance.Create;
begin
  inherited Create;
  FDimScaleOverall := 1;
  FDimlineColor := cnstDefaultEntityColor; // clByBlock;
  FDimStyleItem := TsgTableItem.Create;
end;

procedure TsgDXFTolerance.EndExtData(const AData: TsgCADExtendedData);
begin
  AData.AddString(String_1002, '}');
end;

function TsgDXFTolerance.GetDimlineColor: TsgColorCAD;
begin
  Result := FDimlineColor;
end;

function TsgDXFTolerance.GetDimScaleOverall: Single;
begin
  Result := FDimScaleOverall;
end;

function TsgDXFTolerance.GetDimStyle: TsgDXFDimensionStyle;
begin
  Result := TsgDXFDimensionStyle(FDimStyleItem.Item);
end;

function TsgDXFTolerance.GetEntType: TsgCADEntities;
begin
  Result := ceTolerance;
end;

function TsgDXFTolerance.GetExtData(const AData: TsgCADExtendedData): Boolean;
begin
  BeginExtData(AData);
  AData.AddInt16(Integer_1070, 176);
  AData.AddInt16(Integer_1070,
    ConvertColorCADToIndexColor(DimlineColor, False));
  if Assigned(Style) and (Style.Handle > 0) then
  begin
    AData.AddInt16(Integer_1070, 340);
    AData.AddInt64(String_1005, Style.Handle);
  end;
  AData.AddInt16(Integer_1070, 40);
  AData.AddDouble(Float_1040, DimScaleOverall);
  AData.AddInt16(Integer_1070, 140);
  AData.AddDouble(Float_1040, Height);
  EndExtData(AData);
  Result := AData.DataCount > 0;
end;

function TsgDXFTolerance.GetGAP: Double;
begin
  if FGAP = nil then
  begin
    if DimStyle <> nil then
      Result := DimStyle.TextOffset
    else
      Result := 0;
  end
  else
    Result := FGAP^;
end;

procedure TsgDXFTolerance.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(DimStyle) and (DimStyle.ClassType = TsgLinkObject) then
    DimStyle := TsgDXFDimensionStyle(TsgLinkObject(DimStyle)
      .GetObject(AConverter.Sections[csDimStyles]));
end;

procedure TsgDXFTolerance.LoadedInternal(AConverter: TsgDXFConverter);
var
  vHeight: TsgFloat;
  vPoint: TFPoint;
begin
  if DimStyle = nil then
    DimStyle := AConverter.DimensionStyleByName(sStandardName);
  if Style = nil then
    Style := DimStyle.TextStyle;
  if Style = nil then
    Style := AConverter.StyleByName(sStandardName);
  if FHeight = 0 then
    FHeight := DimStyle.TextHeight;
  vPoint := FPoint;
  vHeight := FHeight;
  try
    // TOLERANCE cell Height := 2*FHeight*DimScaleOverall;
    FHeight := FHeight * DimScaleOverall;
    FPoint.Y := FPoint.Y + FHeight;
    inherited LoadedInternal(AConverter);
  finally
    FHeight := vHeight;
    FPoint := vPoint;
  end;
end;

function TsgDXFTolerance.Parsing(const AConverter: TsgDXFConverter;
  AList: TList; const AColor: TsgColorCAD; ASize: Double): Boolean;
var
  I: Integer;
{$IFNDEF SG_USEDWGVERSION}
  vVersion: Byte;
{$ENDIF}
begin
  if AList = nil then
  begin
    AList := TList.Create;
{$IFNDEF SG_USEDWGVERSION}
    vVersion := AConverter.HeadVarStruct.Version;
    try
      if AConverter.HeadVarStruct.Version = 5 then
        AConverter.FHeadVarStruct.Version := 6;
{$ELSE}
    try
      if (AConverter <> nil) and (AConverter.HeadVarStruct.Version = 5) then
        Result := inherited Parsing(AConverter, AList, DimlineColor, GAP)
      else
{$ENDIF}
        Result := inherited Parsing(AConverter, AList, DimlineColor,
          Height * 2);
      for I := 0 to AList.Count - 1 do
        Block.AddEntity(AList[I]);
    finally
{$IFNDEF SG_USEDWGVERSION}
      AConverter.FHeadVarStruct.Version := vVersion;
{$ENDIF}
      AList.Free;
    end;
  end
  else
    Result := inherited Parsing(AConverter, AList, AColor, ASize);
end;

procedure TsgDXFTolerance.SetDimlineColor(const Value: TsgColorCAD);
begin
  FDimlineColor := Value;
end;

procedure TsgDXFTolerance.SetDimScaleOverall(const Value: Single);
begin
  FDimScaleOverall := Value;
end;

procedure TsgDXFTolerance.SetDimStyle(const Value: TsgDXFDimensionStyle);
begin
  FDimStyleItem.Item := Value;
end;

procedure TsgDXFTolerance.SetGAP(const Value: Double);
begin
  if Abs(Value) > fAccuracy then
  begin
    if FGAP = nil then
      New(FGAP);
    FGAP^ := Value;
  end
  else
  begin
    if FGAP <> nil then
    begin
      Dispose(FGAP);
      FGAP := nil;
    end;
  end;
end;

function TsgDXFTolerance.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlDimScaleOverall].Name).ValueAsDouble :=
    FDimScaleOverall;
end;

procedure TsgDXFTolerance.FreeReferences;
begin
  inherited FreeReferences;
  DisposeAndNil(FGAP);
  FreeAndNil(FDimStyleItem);
end;

function TsgDXFTolerance.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlDimScaleOverall:
      FDimScaleOverall := ANode.ValueAsDouble;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

{$IFDEF SG_BTI}
{ TsgDXFPolyPolyLine }

procedure TsgCADPolyPolyline2D.AddLine(const Value: TsgLine;
  const AFlags: TsgCurveProperties);
var
  vCurve: PF2DCurveEx;
begin
  New(vCurve);
  FCurves.Add(vCurve);
  vCurve^.Flags := AFlags - [lpArc];
  vCurve^.Line.Point1.X := Value.Point1.X;
  vCurve^.Line.Point1.Y := Value.Point1.Y;
  vCurve^.Line.Point2.X := Value.Point2.X;
  vCurve^.Line.Point2.Y := Value.Point2.Y;
end;

procedure TsgCADPolyPolyline2D.AddPoints(const AP1, AP2: TFPoint;
  const AFlags: TsgCurveProperties);
var
  vCurve: PF2DCurveEx;
begin
  New(vCurve);
  FCurves.Add(vCurve);
  vCurve^.Flags := AFlags - [lpArc];
  vCurve^.Line.Point1.X := AP1.X;
  vCurve^.Line.Point1.Y := AP1.Y;
  vCurve^.Line.Point2.X := AP2.X;
  vCurve^.Line.Point2.Y := AP2.Y;
end;

procedure TsgCADPolyPolyline2D.AddArc(const Arc: TsgArcR;
  const AFlags: TsgCurveProperties);
var
  vCurve: PF2DCurveEx;
begin
  New(vCurve);
  FCurves.Add(vCurve);
  vCurve^.Flags := AFlags + [lpArc];
  vCurve^.Arc := Arc;
  vCurve^.Arc.Center.Z := 0;
end;

procedure TsgCADPolyPolyline2D.AddArcCoords(const X, Y, R, A1, A2: Double;
  const AFlags: TsgCurveProperties);
var
  vCurve: PF2DCurveEx;
begin
  New(vCurve);
  FCurves.Add(vCurve);
  vCurve^.Flags := AFlags + [lpArc];
  vCurve^.Arc.Center.X := X;
  vCurve^.Arc.Center.Y := Y;
  vCurve^.Arc.Center.Z := 0;
  vCurve^.Arc.Radius := R;
  vCurve^.Arc.AngleS := A1;
  vCurve^.Arc.AngleE := A2;
end;

procedure TsgCADPolyPolyline2D.AddArcPoints(const AP: TFPoint;
  const R, A1, A2: Double; const AFlags: TsgCurveProperties);
var
  vCurve: PF2DCurveEx;
begin
  New(vCurve);
  FCurves.Add(vCurve);
  vCurve^.Flags := AFlags + [lpArc];
  vCurve^.Arc.Center.X := AP.X;
  vCurve^.Arc.Center.Y := AP.Y;
  vCurve^.Arc.Center.Z := 0;
  vCurve^.Arc.Radius := R;
  vCurve^.Arc.AngleS := A1;
  vCurve^.Arc.AngleE := A2;
end;

procedure TsgCADPolyPolyline2D.AddCoords(const X1, Y1, X2, Y2: Double;
  const AFlags: TsgCurveProperties);
var
  vCurve: PF2DCurveEx;
begin
  New(vCurve);
  FCurves.Add(vCurve);
  vCurve^.Flags := AFlags - [lpArc];
  vCurve^.Line.Point1.X := X1;
  vCurve^.Line.Point1.Y := Y1;
  vCurve^.Line.Point2.X := X2;
  vCurve^.Line.Point2.Y := Y2;
end;

procedure TsgCADPolyPolyline2D.AssignEntity(Source: TsgDXFEntity);
var
  vPolyPolyLine: TsgCADPolyPolyline2D absolute Source;
  I: Integer;
  vCurve: PF2DCurveEx;
begin
  inherited AssignEntity(Source);
  if Source is TsgCADPolyPolyline2D then
  begin
    ClearBox;
    ClearBoundary;
    if FCurves.Count > vPolyPolyLine.FCurves.Count then
    begin
      for I := FCurves.Count - vPolyPolyLine.FCurves.Count downto 0 do
        Dispose(FCurves.List[I]);
      FCurves.Count := vPolyPolyLine.FCurves.Count;
    end
    else
    begin
      while FCurves.Count < vPolyPolyLine.FCurves.Count do
      begin
        New(vCurve);
        FCurves.Add(vCurve);
      end;
    end;
    for I := FCurves.Count - 1 downto 0 do
      PF2DCurveEx(FCurves.List[I])^ :=
        PF2DCurveEx(vPolyPolyLine.FCurves.List[I])^;
  end;
end;

procedure TsgCADPolyPolyline2D.Clear(const ADoFree: Boolean = True);
begin
  ClearBox;
  ClearBoundary;
  ClearRecordList(FCurves, False);
  FCurves.Count := 0;
end;

procedure TsgCADPolyPolyline2D.ClearBoundary;
begin
  FBoundary.Count := 0;
end;

procedure TsgCADPolyPolyline2D.ClearBox;
begin
  if FBox <> nil then
  begin
    Dispose(FBox);
    FBox := nil;
  end;
end;

constructor TsgCADPolyPolyline2D.Create;
begin
  inherited Create;
  FCurves := TList.Create;
  FBoundary := TFPointList.Create;
  FLineWeight := fLineWeightByBlock;
end;

procedure TsgCADPolyPolyline2D.DeleteCurve(const AIndex: Integer);
var
  vCurve: PF2DCurveEx;
begin
  vCurve := FCurves.List[AIndex];
  FCurves.Delete(AIndex);
  Dispose(vCurve);
end;

procedure TsgCADPolyPolyline2D.ClearReferences;
begin
  inherited ClearReferences;
  ClearRecordList(FCurves);
  FBoundary.Clear;
  if Assigned(FDotSingPts) then
    FDotSingPts.Clear;
end;

procedure TsgCADPolyPolyline2D.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FCurves);
  FreeAndNil(FBoundary);
  FreeAndNil(FDotSingPts);
end;

procedure TsgCADPolyPolyline2D.GetBoundary(const AList: TList);

  procedure AddPoint(const ACL: TList; const AP: PF2DPoint);
  var
    P: PFPoint;
  begin
    New(P);
    ACL.Add(P);
    P^.X := AP^.X;
    P^.Y := AP^.Y;
    P^.Z := 0;
  end;

  procedure InsertPoint(const ACL: TList; const AIndex: Integer;
    const AP: PF2DPoint);
  var
    P: PFPoint;
  begin
    New(P);
    ACL.Insert(AIndex, P);
    P^.X := AP^.X;
    P^.Y := AP^.Y;
    P^.Z := 0;
  end;

  function LinesFind(const ACL: TList; const AP: PF2DPoint; var AIndex: Integer;
    var APt: TF2DPoint): Boolean;
  var
    I, Cnt: Integer;
    L: PF2DCurveEx;
  begin
    Result := False;
    Cnt := ACL.Count - 1;
    for I := 0 to Cnt do
    begin
      L := ACL.List[I];
      if lpArc in L^.Flags then
      begin
      end
      else
      begin
        if IsEqualF2DPoints(AP^, L^.Line.Point1) then
        begin
          AIndex := I;
          APt := L^.Line.Point2;
          Result := True;
          Break;
        end
        else if IsEqualF2DPoints(AP^, L^.Line.Point2) then
        begin
          AIndex := I;
          APt := L^.Line.Point1;
          Result := True;
          Break;
        end;
      end;
    end;
  end;

  function GetVector(const AP1, AP2: PFPoint): TFPoint;
  begin
    Result.X := AP2^.X - AP1^.X;
    Result.Y := AP2^.Y - AP1^.Y;
    Result.Z := 0;
  end;

  function GetDistancePoly(const AList: TList): Double;
  begin
    Result := 0;
    if AList.Count > 0 then
      Result := DistanceFPoint2D(PFPoint(AList.List[0])^,
        PFPoint(AList.List[AList.Count - 1])^);
  end;

var
  vLines, vList, vPolylines: TList;
  vLine: PF2DCurveEx;
  vPt, vPtNew: TF2DPoint;
  vIndex: Integer;
  P: PFPoint;
  VB, V1, V2: TFPoint;
  L1, L2, L3: Double;

  procedure CreatePolyBy2Lists;
  var
    J, I: Integer;
    vAngle1, vAngle2: Double;
    vListEx1, vListEx2: TList;
  begin
    vListEx1 := TList(vPolylines.List[0]);
    vListEx2 := TList(vPolylines.List[1]);
    AList.Capacity := vListEx1.Count + vListEx2.Count + 1;
    AList.Count := vListEx1.Count + vListEx2.Count;
    CopyMemory(AList.List, @vListEx1.List[0], vListEx1.Count * SizeOf(Pointer));
    VB := GetVector(vListEx1.List[vListEx1.Count - 1],
      vListEx1.List[vListEx1.Count - 2]);
    V1 := GetVector(vListEx2.List[0], vListEx2.List[1]);
    V2 := GetVector(vListEx2.List[vListEx2.Count - 1],
      vListEx2.List[vListEx2.Count - 2]);
    vAngle1 := GetAngleOfVectors(VB, V1, True);
    vAngle2 := GetAngleOfVectors(VB, V2, True);
    if IsEqual(vAngle1, vAngle2) then
    begin
      P := vListEx1.List[vListEx1.Count - 1];
      if DistanceFPoint(PFPoint(vListEx2.List[0])^, P^) <
        DistanceFPoint(PFPoint(vListEx2.List[vListEx2.Count - 1])^, P^) then
        CopyMemory(@AList.List[vListEx1.Count], @vListEx2.List[0],
          vListEx2.Count * SizeOf(Pointer))
      else
      begin
        J := vListEx1.Count;
        for I := vListEx2.Count - 1 downto 0 do
        begin
          AList.List[J] := vListEx2.List[I];
          Inc(J);
        end;
      end;
    end
    else
    begin
      if vAngle1 < vAngle2 then
        CopyMemory(@AList.List[vListEx1.Count], @vListEx2.List[0],
          vListEx2.Count * SizeOf(Pointer))
      else
      begin
        J := vListEx1.Count;
        for I := vListEx2.Count - 1 downto 0 do
        begin
          AList.List[J] := vListEx2.List[I];
          Inc(J);
        end;
      end;
    end;
  end;

begin
  if FCurves.Count < 1 then
    Exit;
  vLines := TList.Create;
  try
    vLines.Capacity := FCurves.Count;
    vLines.Count := FCurves.Count;
    CopyMemory(vLines.List, @FCurves.List[0], FCurves.Count * SizeOf(Pointer));
    vPolylines := TList.Create;
    try
      repeat
        vList := TList.Create;
        vPolylines.Add(vList);
        vList.Capacity := FCurves.Count;
        vLine := vLines.List[0];
        if lpArc in vLine^.Flags then
        begin

        end
        else
        begin
          AddPoint(vList, @vLine^.Line.Point1);
          AddPoint(vList, @vLine^.Line.Point2);
          vLines.Delete(0);
          vPt := vLine^.Line.Point2;
          while LinesFind(vLines, @vPt, vIndex, vPtNew) do
          begin
            vPt := vPtNew;
            AddPoint(vList, @vPt);
            vLines.Delete(vIndex);
          end;
          if vLines.Count > 0 then
          begin
            vPt := vLine^.Line.Point1;
            while LinesFind(vLines, @vPt, vIndex, vPtNew) do
            begin
              vPt := vPtNew;
              InsertPoint(vList, 0, @vPt);
              vLines.Delete(vIndex);
            end;
          end;
        end;
      until vLines.Count = 0;
      case vPolylines.Count of
        1:
          begin
            vList := vPolylines.List[0];
            AList.Capacity := vList.Count + 1;
            AList.Count := vList.Count;
            CopyMemory(AList.List, @vList.List[0],
              vList.Count * SizeOf(Pointer));
          end;
        2:
          CreatePolyBy2Lists;
        3:
          begin
            L1 := GetDistancePoly(vPolylines.List[0]);
            L2 := GetDistancePoly(vPolylines.List[1]);
            L3 := GetDistancePoly(vPolylines.List[2]);
            if L1 < L2 then
            begin
              if L1 < L3 then
              begin
                SwapPointers(vPolylines.List[0], vPolylines.List[2]);
                SwapSGFloats(L1, L3);
              end;
            end
            else
            begin
              if L2 < L3 then
              begin
                SwapPointers(vPolylines.List[1], vPolylines.List[2]);
                SwapSGFloats(L2, L3);
              end;
            end;
            if (Abs(L1) > fAccuracy) and (Abs(L2) > fAccuracy) then
              CreatePolyBy2Lists;
          end;
      else
        ClearRecordListOfList(vPolylines);
      end;
      if (AList.Count > 1) and not IsEqualFPoints(PFPoint(AList.List[0])^,
        PFPoint(AList.List[AList.Count - 1])^) then
      begin
        New(P);
        AList.Add(P);
        P^ := PFPoint(AList.List[0])^;
      end;
    finally
      FreeList(vPolylines);
    end;
  finally
    vLines.Free;
  end;
end;

function TsgCADPolyPolyline2D.CanDraw: Boolean;
begin
  Result := True;
end;

function TsgCADPolyPolyline2D.GetBox: TFRect;
begin
  if FBox <> nil then
    Result := FBox^
  else
    Result := cnstBadRect;
end;

function TsgCADPolyPolyline2D.GetDotSingPts: TFPointList;
begin
  Result := FDotSingPts;
end;

function TsgCADPolyPolyline2D.GetEntType: TsgCADEntities;
begin
  Result := cePolyPolyline2D;
end;

function TsgCADPolyPolyline2D.GetCurveFlags(const AIndex: Integer)
  : TsgCurveProperties;
begin
  Result := PF2DCurveEx(FCurves.List[AIndex])^.Flags;
end;

function TsgCADPolyPolyline2D.GetArc(const AIndex: Integer): TsgArcR;
begin
  Result := PF2DCurveEx(FCurves.List[AIndex])^.Arc;
end;

function TsgCADPolyPolyline2D.GetLine(const AIndex: Integer): TsgLine;
var
  vCurve: PF2DCurveEx;
begin
  vCurve := FCurves.List[AIndex];
  Result.Point1.X := vCurve^.Line.Point1.X;
  Result.Point1.Y := vCurve^.Line.Point1.Y;
  Result.Point2.X := vCurve^.Line.Point2.X;
  Result.Point2.Y := vCurve^.Line.Point2.Y;
  Result.Point1.Z := 0;
  Result.Point2.Z := 0;
end;

function TsgCADPolyPolyline2D.GroupExists: Boolean;
begin
  Result := True;
end;

function TsgCADPolyPolyline2D.GroupFill(AConverter
  : TsgDXFConverter = nil): Boolean;
var
  I: Integer;
  vEntity: TsgDXFEntity;
  vArc: TsgArcR;
  vLine: TsgLine;

  procedure Loaded(E: TsgDXFEntity);
  begin
    E.Loaded(AConverter);
  end;

begin
  for I := 0 to CurvesCount - 1 do
  begin
    vEntity := nil;
    if CurveVisible[I] then
    begin
      if IsCurveArc(I) then
      begin
        vEntity := TsgDXFArc.Create;
        vArc := Arcs[I];
        TsgDXFArc(vEntity).Extrusion := cnstExtrusion;
        TsgDXFArc(vEntity).Point := vArc.Center;
        TsgDXFArc(vEntity).Radius := vArc.Radius;
        TsgDXFArc(vEntity).ZThick := 0;
        TsgDXFArc(vEntity).StartAngle := vArc.AngleS;
        TsgDXFArc(vEntity).EndAngle := vArc.AngleE;
      end
      else
      begin
        vLine := Lines[I];
        vEntity := TsgDXFLine.Create;
        TsgDXFLine(vEntity).Point := vLine.Point1;
        TsgDXFLine(vEntity).Point1 := vLine.Point2;
      end;
    end;
    if vEntity <> nil then
    begin
      vEntity.AssignEntity(Self);
      vEntity.LineType := LineType;
      Loaded(vEntity);
      Group.AddEntity(vEntity);
    end;
  end;
  Result := Group.Count > 0;
end;

function TsgCADPolyPolyline2D.GroupHasAddedEntities: Boolean;
begin
  Result := True;
end;

function TsgCADPolyPolyline2D.GetCurveJoin(const AIndex: Integer): Boolean;
begin
  Result := lpJoin in PF2DCurveEx(FCurves.List[AIndex])^.Flags;
end;

function TsgCADPolyPolyline2D.GetCurvesCount: Integer;
begin
  Result := FCurves.Count;
end;

function TsgCADPolyPolyline2D.GetCurvesVisible(const AIndex: Integer): Boolean;
begin
  Result := lpVisible in PF2DCurveEx(FCurves.List[AIndex])^.Flags;
end;

function TsgCADPolyPolyline2D.GetLineWeight: Double;
begin
  Result := FLineWeight;
end;

procedure TsgCADPolyPolyline2D.GetPointsOfArc(const AIndex: Integer;
  const A3DPointsList: TFPointList; const A2DPointsList: TsgIntegerList;
  NumberPart: Integer; Proc: TsgObjProcGetPoint = nil);
var
  Arc: TsgArcR;
  vAngle, vStart, vEnd, vAngleDelta: Double;
  S, C: Extended;
  I: Integer;
  vPnt: TFPoint;
  vPoint: TPoint;
begin
  Arc := Arcs[AIndex];
  if NumberPart < 3 then
    NumberPart := GetNumberOfCircleParts;
  vStart := Arc.AngleS;
  vEnd := Arc.AngleE;
  if vStart > vEnd then
    vStart := vStart - Round(vStart / 360) * 360;
  if vEnd < vStart then
    vEnd := vEnd + 360;
  vAngleDelta := (vEnd - vStart) * fPiDividedBy180 / NumberPart;
  vAngle := vStart * fPiDividedBy180;
  vPnt.Z := 0;
  for I := 0 to NumberPart do
  begin
    SinCos(vAngle, S, C);
    vAngle := vAngle + vAngleDelta;
    vPnt.X := Arc.Center.X + C * Arc.Radius;
    vPnt.Y := Arc.Center.Y + S * Arc.Radius;
    if Assigned(A2DPointsList) then
    begin
      vPoint := Proc(vPnt);
      A2DPointsList.Add(vPoint.X);
      A2DPointsList.Add(vPoint.Y);
    end;
    if Assigned(A3DPointsList) then
      A3DPointsList.Add(vPnt);
  end;
end;

function TsgCADPolyPolyline2D.IsLoaded: Boolean;
begin
  Result := FBox <> nil;
end;

function TsgCADPolyPolyline2D.IsCurveArc(const AIndex: Integer): Boolean;
begin
  Result := lpArc in PF2DCurveEx(FCurves.List[AIndex])^.Flags;
end;

procedure TsgCADPolyPolyline2D.LoadBoundary;
var
  vBoundaries, vCurves: TList;
begin
  ClearBoundary;
  if FCurves.Count < 1 then
    Exit;
  FBoundary.Capacity := FCurves.Count shl 1;
  vBoundaries := TList.Create;
  vCurves := TList.Create;
  try
    CopyLists(vCurves, FCurves);
    SortBoundariesLists(vCurves, vBoundaries, GetPoint1OfPF2DCurveEx,
      GetPoint2OfPF2DCurveEx, CopyForwardPF2DCurveEx,
      CopyBackwardPF2DCurveEx, False);
    if vBoundaries.Count > 0 then
    begin
      FBoundary.Free;
      FBoundary := vBoundaries.List[0];
      vBoundaries.Delete(0);
    end;
  finally
    vCurves.Free;
    FreeList(vBoundaries);
  end;
end;

procedure TsgCADPolyPolyline2D.LoadedInternal(AConverter: TsgDXFConverter);
var
  I: Integer;
  vLine: TF2DLine;
  vArc: TsgArcR;
  vLineType: TsgDXFLineType;
  vLTScale: Single;
  vBox: TFRect;

  procedure ExpandFRect2DEx(var R: TFRect; const P: TF2DPoint);
  begin
    if R.Left > P.X then
      R.Left := P.X;
    if R.Top < P.Y then
      R.Top := P.Y;
    if R.Right < P.X then
      R.Right := P.X;
    if R.Bottom > P.Y then
      R.Bottom := P.Y;
  end;

begin
  inherited LoadedInternal(AConverter);
  ClearBox;
  ClearBoundary;
  if DotSingPts <> nil then
  begin
    FDotSingPts.Free;
    FDotSingPts := nil;
  end;
  if Layer = nil then
    Layer := AConverter.LayerByName('0');
  if FCurves.Count > 0 then
  begin
    vBox := cnstBadRect;
    vBox.Z1 := 0;
    vBox.Z2 := 0;
    LoadBoundary;
    // for I := 0 to FBoundary.Count - 1 do
    // ExpandFRect2D(vBox, PFPoint(FBoundary.List^[I])^);
    if (LineType = nil) or (LineType.Lines.IsSolid) then
    begin
      for I := FCurves.Count - 1 downto 0 do
      begin
        if CurveVisible[I] then
        begin
          if IsCurveArc(I) then
          begin
            vArc := PF2DCurveEx(FCurves.List[I])^.Arc;
            ArcExpandFRect2D(vBox, vArc, True);
          end
          else
          begin
            vLine := PF2DCurveEx(FCurves.List[I])^.Line;
            ExpandFRect2DEx(vBox, vLine.Point1);
            ExpandFRect2DEx(vBox, vLine.Point2);
          end;
        end;
      end;
    end
    else
    begin
      FDotSingPts := TFPointList.Create;
      FDotSingPts.Capacity := FCurves.Count shl 2 + 1;
      vLineType := LineType;
      vLTScale := vLineType.Lines.Scale;
      vLineType.Lines.Scale := vLTScale * AConverter.GetLTScale *
        FLineTypeScale;
      try
        for I := FCurves.Count - 1 downto 0 do
        begin
          if CurveVisible[I] then
          begin
            if IsCurveArc(I) then
            begin
              vArc := PF2DCurveEx(FCurves.List[I])^.Arc;
              ArcExpandFRect2D(vBox, vArc, True);
            end
            else
            begin
              vLine := PF2DCurveEx(FCurves.List[I])^.Line;
              ExpandFRect2DEx(vBox, vLine.Point1);
              ExpandFRect2DEx(vBox, vLine.Point2);
              vLineType.Lines.Line(MakeFPoint(vLine.Point1.X, vLine.Point1.Y,
                0), MakeFPoint(vLine.Point2.X, vLine.Point2.Y, 0), FDotSingPts);
            end;
          end;
        end;
      finally
        vLineType.Lines.Scale := vLTScale;
      end;
    end;
    if not IsBadRect(vBox) then
    begin
      New(FBox);
      FBox^ := vBox;
    end;
  end;
end;

procedure TsgCADPolyPolyline2D.SetArc(const AIndex: Integer;
  const Value: TsgArcR);
begin
  PF2DCurveEx(FCurves.List[AIndex])^.Arc := Value;
  PF2DCurveEx(FCurves.List[AIndex])^.Arc.Center.Z := 0;
end;

procedure TsgCADPolyPolyline2D.SetCurveFlags(const AIndex: Integer;
  const Value: TsgCurveProperties);
begin
  PF2DCurveEx(FCurves.List[AIndex])^.Flags := Value;
end;

procedure TsgCADPolyPolyline2D.SetCurveJoin(const AIndex: Integer;
  const Value: Boolean);
var
  vCurve: PF2DCurveEx;
begin
  vCurve := FCurves.List[AIndex];
  if Value then
    vCurve.Flags := vCurve^.Flags + [lpJoin]
  else
    vCurve.Flags := vCurve^.Flags - [lpJoin];
end;

procedure TsgCADPolyPolyline2D.SetLines(const AIndex: Integer;
  const Value: TsgLine);
var
  vCurve: PF2DCurveEx;
begin
  vCurve := FCurves.List[AIndex];
  vCurve^.Line.Point1.X := Value.Point1.X;
  vCurve^.Line.Point1.Y := Value.Point1.Y;
  vCurve^.Line.Point2.X := Value.Point2.X;
  vCurve^.Line.Point2.Y := Value.Point2.Y;
end;

procedure TsgCADPolyPolyline2D.SetLineVisible(const AIndex: Integer;
  const Value: Boolean);
var
  vCurve: PF2DCurveEx;
begin
  vCurve := FCurves.List[AIndex];
  if Value then
    vCurve^.Flags := vCurve^.Flags + [lpVisible]
  else
    vCurve^.Flags := vCurve^.Flags - [lpVisible];
end;

procedure TsgCADPolyPolyline2D.SetLineWeight(Value: Double);
begin
  FLineWeight := Value;
end;

procedure TsgCADPolyPolyline2D.SetHandle(const Value: UInt64);
begin
{$IFDEF SG_MODULE_LOG}
  inherited SetHandle(Value);
{$ENDIF}
end;

{ TsgAttrib }

procedure TsgAttrib.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgAttrib then
  begin
    FType := TsgAttrib(Source).FType;
    // FOwner := TsgAttrib(Source).FOwner;
  end;
end;

function TsgAttrib.BeginExtData(const AData: TsgCADExtendedData): Boolean;
begin
  AData.AddString(String_1001, GetAppID);
  AData.AddString(String_1002, '{');
  Result := True;
end;

procedure TsgAttrib.EndExtData(const AData: TsgCADExtendedData);
begin
  AData.AddString(String_1002, '}');
end;

function TsgAttrib.GetExtData(const AData: TsgCADExtendedData): Boolean;
begin
  BeginExtData(AData);
  AData.AddInt16(Integer_1070, Word_280);
  AData.AddInt16(Integer_1070, Ord(TypeValue));
  EndExtData(AData);
  Result := True;
end;

constructor TsgAttrib.Create;
begin
  inherited Create;
  FType := atString;
end;

function TsgAttrib.GetAttribIndex: Integer;
var
  vExData: TsgExtendedBlockData;
  vTag: string;
begin
  vExData := ExBlockData;
  vTag := AnsiUpperCase(Tag);
  for Result := 0 to vExData.AttributesCount - 1 do
    if (AnsiUpperCase(vExData.Attributes[Result].Name) = vTag) and
      (vExData.Attributes[Result].AttribType = TypeValue) then
      Exit;
  Result := -1;
end;

function TsgAttrib.GetExBlockData: TsgExtendedBlockData;
var
  vInsert: TsgDXFInsert;
begin
  Result := nil;
  if Owner is TsgDXFInsert then
  begin
    vInsert := TsgDXFInsert(Owner);
    if vInsert.GetExtendedData <> nil then
      Result := vInsert.GetExtendedBlockData;
  end;
end;

function TsgAttrib.GetIndexValue: Integer;
begin
  case FType of
    atEnum:
      Result := Values.IndexOf(Value);
  else
    Result := -1;
  end;
end;

function TsgAttrib.GetTypeValue: TsgAttribType;
begin
  Result := FType;
end;

function TsgAttrib.GetValues: TStringList;
var
  vExData: TsgExtendedBlockData;
begin
  Result := nil;
  vExData := ExBlockData;
  if (AttribIndex <> -1) and (vExData.AttributesCount > 0) and
    (vExData.Attributes[AttribIndex].AttribType = atEnum) then
    Result := vExData.Attributes[AttribIndex].Values;
end;

procedure TsgAttrib.SetTypeValue(const Value: TsgAttribType);
begin
  FType := Value;
end;

procedure TsgAttrib.SetIndexValue(const AIndex: Integer);
begin
  Value := Values[AIndex];
end;

{ TsgGroup }

function TsgGroup.AddBlock(const AConverter: TsgDXFConverter): Boolean;
var
  vName, vBlockName: string;
  vIndex: TsgNativeUInt;
begin
  if Block = nil then
    CreateBlock;
  if (AConverter <> nil) and (Length(Block.Name) = 0) then
  begin
    vName := ShortName + '_';
    vIndex := TsgNativeUInt(Block) - 1;
    repeat
      Inc(vIndex);
      vBlockName := vName + IntToStr(vIndex);
    until AConverter.BlockByName(vBlockName) = nil;
    Block.Name := vBlockName;
    AConverter.Sections[csBlocks].AddEntity(Block);
  end;
  Result := Length(Block.Name) > 0;
end;

constructor TsgGroup.Create;
begin
  inherited Create;
  CreateBlock;
end;

procedure TsgGroup.CreateBlock;
begin
  Block := TsgDXFBlock.Create;
  Block.SetFlags(1);
end;

destructor TsgGroup.Destroy;
begin
  // FreeBlock;
  inherited Destroy;
end;

function TsgGroup.FreeBlock: Boolean;
var
  vBlock: TsgDXFBlock;
  vConverter: TsgDXFConverter;
begin
  Result := (Block <> nil) and CanFreeBlock(Converter);
  if Result then
  begin
    vBlock := Block;
    vConverter := Converter;
    Block := nil;
    if Assigned(vConverter) then
      vConverter.DeleteBlock(vBlock, False);
    vBlock.Free;
  end;
end;

function TsgGroup.CanFreeBlock(AConverter: TsgDXFConverter): Boolean;
begin
  Result := (AConverter = nil) or (AConverter.Status in [stDefault, stEditing]);
end;

function TsgGroup.CanLoading(AConverter: TsgDXFConverter): Boolean;
begin
  Result := (AConverter <> nil) and (AConverter.Status = stDefault);
end;

procedure TsgGroup.ClearBlock;
begin
  if Block <> nil then
    Block.Clear(True);
end;

procedure TsgGroup.ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord);
begin
  // not implement
end;

function TsgGroup.ReMoveBlock(const AConverter: TsgDXFConverter): Boolean;
begin
  Result := False;
  if (AConverter <> nil) and (Block <> nil) and AConverter.DeleteBlock(Block,
    False) then
  begin
    SetConverter(nil);
    Block.Name := '';
    Result := True;
  end;
end;

function TsgGroup.ShortName: string;
begin
  Result := '*G';
end;

{ TsgLabel }

procedure TsgLabel.AssignEntity(Source: TsgDXFEntity);
var
  vLabel: TsgLabel absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgLabel then
  begin
    FEntOwner := vLabel.FEntOwner;
    CopyFrom(vLabel);
  end;
end;

procedure TsgLabel.CopyFrom(Source: TsgLabel);
begin
  if Block <> nil then
    Block.Clear(True);
  ColorCAD := Source.ColorCAD;
  FFlags := Source.FFlags;
  FTextLeft := Source.FTextLeft;
  FTextRight := Source.FTextRight;
  FTextTop := Source.FTextTop;
  FTextBottom := Source.FTextBottom;
  Style := Source.Style;
  FHeight := Source.FHeight;
  FTextOffset := Source.FTextOffset;
end;

function TsgLabel.BeginExtData(const AData: TsgCADExtendedData): Boolean;
begin
  AData.AddString(String_1001, GetAppID);
  // AData.AddString(String_1000, Copy(ClassName, 4, MaxInt));
  AData.AddString(String_1002, '{');
  AData.AddInt16(Integer_1070, Integer_70);
  AData.AddInt(Integer_1071, GetEntTypeEx, Integer_1070);
  Result := True;
end;

procedure TsgLabel.EndExtData(const AData: TsgCADExtendedData);
begin
  AData.AddString(String_1002, '}');
end;

function TsgLabel.GetExtData(const AData: TsgCADExtendedData): Boolean;
begin
  BeginExtData(AData);
  AData.AddInt16(Integer_1070, Integer_290);
  AData.AddInt16(Integer_1070, Ord(ShowSplitter));
  AData.AddInt16(Integer_1070, Integer_400);
  AData.AddInt16(Integer_1070, Align);
  AData.AddInt16(Integer_1070, Float_140);
  AData.AddDouble(Float_1041, Height);
  AData.AddInt16(Integer_1070, Float_141);
  AData.AddDouble(Float_1041, TextOffset);
  if Style <> nil then
  begin
    AData.AddInt16(Integer_1070, String_430);
    AData.AddString(String_1000, Style.Name, String_1005);
  end;
  AData.AddInt16(Integer_1070, String_431);
  AData.AddString(String_1000, TextLeft, String_1005);
  AData.AddInt16(Integer_1070, String_432);
  AData.AddString(String_1000, TextRight, String_1005);
  AData.AddInt16(Integer_1070, String_433);
  AData.AddString(String_1000, TextTop, String_1005);
  AData.AddInt16(Integer_1070, String_434);
  AData.AddString(String_1000, TextBottom, String_1005);
  EndExtData(AData);
  Result := AData.DataCount > 0;
end;

function TsgLabel.EntName: string;
begin
  Result := GetClassEntName(Self, 3);
end;

constructor TsgLabel.Create;
begin
  inherited Create;
  FTextStyleItem := TsgTableItem.Create;
  ShowSplitter := True;
  Align := 5;
end;

procedure TsgLabel.ClearReferences;
begin
  inherited ClearReferences;
  FTextStyleItem.Item := nil;
end;

procedure TsgLabel.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FTextStyleItem);
end;

destructor TsgLabel.Destroy;
begin
  inherited Destroy;
end;

function TsgLabel.GenerateLabel(const AConverter: TsgDXFConverter): Boolean;
// TextTop
// TextLeft ------ TextRight
// TextBottom
var
  vTexts: array [1 .. 4] of TsgDXFText;
  vLine: TsgLine;
  vEntLine: TsgDXFLine;
  X3, X4, vLen, vLeft, vRight: Double;
  vText: string;

  function CreateText(const AText: string): TsgDXFText;
  begin
    Result := TsgDXFText.Create;
    Result.Layer := Layer;
    Result.Point := cnstFPointZero;
    Result.Style := Style;
    Result.Height := FHeight;
    Result.ColorCAD := cnstColorCADByBlock;
    Result.LineWeight := fLineWeightByBlock;
    Result.Text := AText;
    Result.ApplyStyle(Style);
    // Result.ObliqueAngle := FStyle.ObliqueAngle;//This in TsgDXFText.ApplyStyle
    // Result.XScale := FStyle.WidthFactor;
    Result.Loaded(AConverter);
  end;

  function GetEntWidth(const AEnt: TsgDXFEntity): Double;
  begin
    if IsBadRect(AEnt.Box) then
      Result := 0
    else
      Result := AEnt.Box.Right - AEnt.Box.Left;
  end;

  function GetEntHeight(const AEnt: TsgDXFEntity): Double;
  begin
    if IsBadRect(AEnt.Box) then
      Result := 0
    else
      Result := AEnt.Box.Top - AEnt.Box.Bottom;
  end;

begin
  Block.Clear(True);
  Block.Offset := cnstFPointZero;
  FillChar(vTexts, SizeOf(vTexts), 0);
  vText := GetTextTopShow;
  if Length(vText) > 0 then
  begin
    vTexts[3] := CreateText(vText);
    X3 := GetEntWidth(vTexts[3]);
  end
  else
    X3 := 0;
  vText := GetTextBottomShow;
  if Length(vText) > 0 then
  begin
    vTexts[4] := CreateText(vText);
    X4 := GetEntWidth(vTexts[4]);
  end
  else
    X4 := 0;
  vLen := Max(X3, X4);
  if (vLen < fAccuracy) and ShowSplitter then
    vLen := FHeight * 6;
  vLine.Point1 := MakeFPoint(-vLen * 0.5, 0, 0);
  vLine.Point2 := MakeFPoint(vLen * 0.5, 0, 0);
  vLeft := MaxDouble;
  vRight := -MaxDouble;
  if vTexts[3] <> nil then
  begin
    vTexts[3].Point := MakeFPoint(vLine.Point1.X + (vLen - X3) * 0.5,
      TextOffset, 0);
    Block.AddEntity(vTexts[3]);
    vTexts[3].Loaded(AConverter);
    if vLeft > vTexts[3].Box.Left then
      vLeft := vTexts[3].Box.Left;
    if vRight < vTexts[3].Box.Right then
      vRight := vTexts[3].Box.Right;
  end;
  if vTexts[4] <> nil then
  begin
    vTexts[4].Point := MakeFPoint(vLine.Point1.X + (vLen - X4) * 0.5,
      -TextOffset - GetEntHeight(vTexts[4]), 0);
    Block.AddEntity(vTexts[4]);
    vTexts[4].Loaded(AConverter);
    if vLeft > vTexts[4].Box.Left then
      vLeft := vTexts[4].Box.Left;
    if vRight < vTexts[4].Box.Right then
      vRight := vTexts[4].Box.Right;
  end;
  if vLeft < vRight then
  begin
    vLine.Point1.X := vLeft;
    vLine.Point2.X := vRight;
  end;
  vText := GetTextLeftShow;
  if Length(vText) > 0 then
  begin
    vTexts[1] := CreateText(vText);
    vTexts[1].Point := MakeFPoint(vLine.Point1.X - GetEntWidth(vTexts[1]) -
      TextOffset, vLine.Point1.Y - GetEntHeight(vTexts[1]) * 0.5, 0);
    Block.AddEntity(vTexts[1]);
    vTexts[1].Loaded(AConverter);
  end;
  vText := GetTextRightShow;
  if Length(vText) > 0 then
  begin
    vTexts[2] := CreateText(vText);
    vTexts[2].Point := MakeFPoint(vLine.Point2.X + TextOffset,
      vLine.Point1.Y - GetEntHeight(vTexts[2]) * 0.5, 0);
    Block.AddEntity(vTexts[2]);
    vTexts[2].Loaded(AConverter);
  end;
  if ShowSplitter and (Block.Count > 0) then
  begin
    vEntLine := TsgDXFLine.Create;
    Block.AddEntity(vEntLine);
    vEntLine.ColorCAD := cnstColorCADByBlock;
    vEntLine.Layer := Layer;
    vEntLine.LineWeight := fLineWeightByBlock;
    vEntLine.LineTypeScale := LineTypeScale;
    vEntLine.Point := vLine.Point1;
    vEntLine.Point1 := vLine.Point2;
    vEntLine.Loaded(AConverter);
  end;
  Block.Offset := cnstFPointZero;
  Block.Loaded(AConverter);
  Result := Block.Count > 0;
end;

function TsgLabel.GetAlign: Byte;
begin
  Result := FFlags and 15;
end;

function TsgLabel.GetEntClassEx: TsgEntClass;
begin
  Result.EG := gtBTI;
  Result.ET.BTI := GetBTITypeByEntTypeEx(GetEntTypeEx);
end;

function TsgLabel.GetEntType: TsgCADEntities;
begin
  Result := inherited GetEntType;
end;

function TsgLabel.GetEntTypeEx: Integer;
begin
  Result := cnstLabel;
end;

function TsgLabel.GetHeight: TsgFloat;
begin
  Result := FHeight;
end;

function TsgLabel.GetTextLeft: string;
begin
  Result := FTextLeft;
end;

function TsgLabel.GetTextLeftShow: string;
begin
  Result := GetTextLeft;
end;

function TsgLabel.GetTextRight: string;
begin
  Result := FTextRight;
end;

function TsgLabel.GetTextRightShow: string;
begin
  Result := GetTextRight;
end;

function TsgLabel.GetTextTop: string;
begin
  Result := FTextTop;
end;

function TsgLabel.GetTextTopShow: string;
begin
  Result := GetTextTop;
end;

function TsgLabel.GetTextBottom: string;
begin
  Result := FTextBottom;
end;

function TsgLabel.GetTextBottomShow: string;
begin
  Result := GetTextBottom;
end;

function TsgLabel.GetShowSplitter: Boolean;
begin
  Result := (FFlags and 16) <> 0;
end;

function TsgLabel.GetStyle: TsgDXFStyle;
begin
  Result := TsgDXFStyle(FTextStyleItem.Item);
end;

function TsgLabel.GetTextOffset: TsgFloat;
begin
  Result := FTextOffset;
end;

procedure TsgLabel.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(Style) and (Style.ClassType = TsgLinkObject) then
    Style := TsgDXFStyle(TsgLinkObject(Style)
      .GetObject(AConverter.Sections[csStyles]));
end;

procedure TsgLabel.LoadedInternal(AConverter: TsgDXFConverter);
var
  X, Y, vDX, vDY: Double;
  vOffset: TFPoint;
begin
  FBox := cnstBadRect;
  if CanLoading(AConverter) then
  begin
    AddBlock(AConverter);
    if Layer = nil then
      Layer := Converter.LayerByName('0');
    if Style = nil then
      Style := Converter.StyleByName(sStandardName);
    if GenerateLabel(AConverter) then
    begin
      Block.IsLoaded := False;
      Block.Loaded(AConverter);
      X := Block.Box.Right - Block.Box.Left;
      Y := Block.Box.Top - Block.Box.Bottom;
      vDX := (Abs(Block.Box.Right) - Abs(Block.Box.Left)) * 0.5;
      vDY := (Abs(Block.Box.Top) - Abs(Block.Box.Bottom)) * 0.5;
      vOffset := Block.Offset;
      case Align of
        0, 1, 4, 7:
          vOffset.X := vOffset.X - X * 0.5 + vDX;
        2, 5, 8:
          vOffset.X := vOffset.X + vDX;
        3, 6, 9:
          vOffset.X := vOffset.X + X * 0.5 + vDX;
      end;
      case Align of
        0, 1, 2, 3:
          vOffset.Y := vOffset.Y + Y * 0.5 + vDY;
        4, 5, 6:
          vOffset.Y := vOffset.Y + vDY;
        7, 8, 9:
          vOffset.Y := vOffset.Y - Y * 0.5 + vDY;
      end;
      Block.Offset := vOffset;
      FBox := Block.Box;
      CalculateMatrix;
      if not IsBadRect(FBox) then
        TransRectCorners(FBox, FMatrix);
    end;
  end;
end;

procedure TsgLabel.SetAlign(const Value: Byte);
begin
  FFlags := (FFlags and 240) or (Value and 15);
end;

procedure TsgLabel.SetHeight(const Value: TsgFloat);
begin
  FHeight := Value;
end;

procedure TsgLabel.SetTextLeft(const Value: string);
begin
  FTextLeft := Value;
end;

procedure TsgLabel.SetTextRight(const Value: string);
begin
  FTextRight := Value;
end;

procedure TsgLabel.SetTextTop(const Value: string);
begin
  FTextTop := Value;
end;

procedure TsgLabel.SetTextBottom(const Value: string);
begin
  FTextBottom := Value;
end;

procedure TsgLabel.SetShowSplitter(const Value: Boolean);
begin
  FFlags := (FFlags and 239) or (Byte(Value) shl 4);
end;

procedure TsgLabel.SetStyle(const Value: TsgDXFStyle);
begin
  FTextStyleItem.Item := Value;
end;

procedure TsgLabel.SetTextOffset(const Value: TsgFloat);
begin
  FTextOffset := Abs(Value);
end;

function TsgLabel.ShortName: string;
begin
  Result := '*L';
end;

{ TsgAreaFigure }

procedure TsgAreaFigure.Assign(const AObj: TObject);
var
  vObj: TsgAreaFigure absolute AObj;
begin
  if AObj is TsgAreaFigure then
  begin
    FFlags := vObj.FFlags;
    FType := vObj.FType;
    FKoef := vObj.FKoef;
    FName := vObj.FName;
    CopyMemory(@FParams[0], @vObj.FParams[0], SizeOf(vObj.FParams));
    FFlags := vObj.FFlags;
  end;
end;

constructor TsgAreaFigure.Create;
begin
  FType := ftFigure;
  FKoef := 1;
  Sign := 1;
end;

destructor TsgAreaFigure.Destroy;
begin
  // FType := ftFigure;
  inherited Destroy;
end;

function TsgAreaFigure.GetArea: Double;
var
  vP, vRadius, vHeight: Double;
begin
  case FType of
    ftRect:
      Result := A * B;
    ftSquare:
      Result := Sqr(A);
    ftQuadrangle:
      Result := 0.5 * C * D * Sin(A * fPiDividedBy180);
    ftParallelogram:
      Result := B * H;
    ftRhomb:
      Result := C * D * 0.5;
    ftTrapezium:
      Result := (A + B) * H * 0.5;
    ftTriangle:
      begin
        vP := (A + B + C) * 0.5;
        Result := vP * (vP - A) * (vP - B) * (vP - C);
        if Result > fAccuracy then
          Result := Sqrt(Result)
        else
          Result := -1;
      end;
    ftTriangleRightAngled:
      Result := A * B * 0.5;
    ftTriangleByHippuran:
      begin
        vP := Sqr(C) - Sqr(A);
        if vP > fAccuracy then
          Result := A * Sqrt(vP) * 0.5
        else
          Result := -1;
      end;
    ftCircleByLength:
      Result := Sqr(L) / cnstPiMul4;
    ftCircleByRadius:
      Result := cnstPi * Sqr(R);
    ftSectorByAngleAndRadius:
      Result := Sqr(R) * A * fPiDividedBy180;
    ftSegmentByChordAndLength:
      begin
        Result := -1;
        if (A > fAccuracy) and (L > fAccuracy) then
        begin
          vHeight := GetHeightByChordAndLength(A, L);
          if vHeight > fAccuracy then
          begin
            vRadius := GetRadiusByChordAndHeight(A, vHeight);
            if vRadius > fAccuracy then
              Result := 0.5 * (L * vRadius - A * (vRadius - vHeight))
          end;
        end;
      end;
    ftSegmentByChordAndHeight:
      begin
        Result := -1;
        if (A > fAccuracy) and (H > fAccuracy) then
        begin
          vRadius := GetRadiusByChordAndHeight(A, H);
          if vRadius > fAccuracy then
            Result := 0.5 * (GetAngleByChordAndRadius(A, vRadius) * Sqr(vRadius)
              - A * (vRadius - H));
        end;
      end;
    ftContour:
      Result := S;
  else
    Result := 0;
  end;
  if Result > fAccuracy then
    Result := Sqr(FKoef) * Result;
end;

function TsgAreaFigure.GetExtData(const AData: TsgCADExtendedData): Boolean;
var
  J: Integer;
begin
  AData.AddInt16(Integer_1070, Integer_170);
  AData.AddInt16(Integer_1070, Ord(FType));
  AData.AddInt16(Integer_1070, String_439);
  AData.AddString(String_1000, FName, String_1005);
  AData.AddInt16(Integer_1070, Word_289);
  AData.AddInt16(Integer_1070, FFlags);
  AData.AddInt16(Integer_1070, Float_239);
  AData.AddDouble(Float_1041, FKoef);
  AData.AddInt16(Integer_1070, FloatRepeated_49);
  for J := Low(FParams) to High(FParams) do
    AData.AddDouble(Float_1042, FParams[J]);
  Result := True;
end;

function TsgAreaFigure.GetAreaStr(const APrecition: Integer;
  const ASeparator: Char = ','): string;
begin
  Result := AreaToStr(Area, APrecition, GetDecimalSeparator);
end;

function TsgAreaFigure.GetFormula(const APrecition: Integer;
  const ASeparator: Char = ','): string;
const
  sAD = ' + ';
  sCP = '; ';
  sDV = ' / ';
  sML = ' * ';
  sSB = ' - ';
  sPI = 'Pi';
  s1Div2 = '0.5';
  sSS = '(';
  sSE = ')';
  sSQ = '=';

  procedure SetParam(const AValue: Double; var Rez: string);
  begin
    Rez := DoubleToStrVisualRound_(AValue * FKoef, APrecition, ASeparator);
  end;

  function Param(const AIndex: Integer): string;
  begin
    case AIndex of
      0:
        SetParam(A, Result);
      1:
        SetParam(B, Result);
      2:
        SetParam(C, Result);
      3:
        SetParam(D, Result);
      4:
        SetParam(H, Result);
      5:
        SetParam(L, Result);
      6:
        SetParam(R, Result);
      7:
        SetParam(S, Result);
    else
      Result := DoubleToStrF(A, 2, ASeparator);
    end;
  end;

  function AddSqr(const AIndex: Integer): string;
  begin
    Result := sSqr + sSS + Param(AIndex) + sSE;
  end;

begin
  case FType of
    ftRect:
      Result := Param(0) + sML + Param(1);
    ftSquare:
      Result := AddSqr(0);
    ftQuadrangle:
      Result := s1Div2 + sML + Param(2) + sML + Param(3) + sML + sSin + sSS +
        Param(7) + sSE;
    ftParallelogram:
      Result := Param(1) + sML + Param(4);
    ftRhomb:
      Result := s1Div2 + sML + Param(2) + sML + Param(3);
    ftTrapezium:
      Result := s1Div2 + sML + sSS + Param(0) + sAD + Param(1) + sSE + sML
        + Param(4);

    ftTriangle:
      Result := sGeron + sSS + Param(0) + sCP + Param(1) + sCP + Param(2) + sSE;
    ftTriangleRightAngled:
      Result := s1Div2 + sML + Param(0) + sML + Param(1);
    ftTriangleByHippuran:
      Result := s1Div2 + sML + Param(0) + sML + sSqrt + sSS + AddSqr(2) + sSB +
        AddSqr(0) + sSE;

    ftCircleByLength:
      Result := AddSqr(5) + sDV + sSS + '4' + sML + sPI + sSE;
    ftCircleByRadius:
      Result := sPI + sML + AddSqr(6);

    ftSectorByAngleAndRadius:
      Result := AddSqr(6) + sML + sRadin + sSS + Param(7) + sSE;
    ftSegmentByChordAndLength:
      Result := sSegmentAL + sSS + Param(0) + sCP + Param(5) + sSE;
    ftSegmentByChordAndHeight:
      Result := sSegmentAH + sSS + Param(0) + sCP + Param(4) + sSE;
    ftContour:
      Result := cnstAreaFigues[ftContour] + sSS + Param(7) + sSE;
  else
    Result := sUNKNOWN;
  end;
end;

function TsgAreaFigure.GetInfo(const APrecition: Integer;
  const ASeparator: Char = ','): string;

  procedure SetParam(const AName: string; const AValue: Double;
    var Rez: string);
  begin
    Rez := ' ' + AName + ' = ' + DoubleToStrVisualRound_(AValue * FKoef,
      APrecition, ASeparator);
  end;

  function Param(const AIndex: Integer): string;
  begin
    case AIndex of
      0:
        SetParam('A', A, Result); // A
      1:
        SetParam('B', B, Result); // B
      2:
        SetParam('C', C, Result); // C
      3:
        SetParam('D', D, Result); // D
      4:
        SetParam('H', H, Result); // H
      5:
        SetParam('L', L, Result); // L
      6:
        SetParam('R', R, Result); // R
      7:
        SetParam('S', S, Result); // S
    else
      Result := ' a = ' + DoubleToStrF(A, 2, ASeparator) // a
    end;
  end;

begin
  Result := Name;
  case FType of
    ftRect:
      Result := Result + Param(0) + Param(1);
    ftSquare:
      Result := Result + Param(0);
    ftQuadrangle:
      Result := Result + Param(2) + Param(3) + Param(7);
    ftParallelogram:
      Result := Result + Param(1) + Param(4);
    ftRhomb:
      Result := Result + Param(2) + Param(3);
    ftTrapezium:
      Result := Result + Param(0) + Param(1) + Param(4);

    ftTriangle:
      Result := Result + Param(0) + Param(1) + Param(2);
    ftTriangleRightAngled:
      Result := Result + Param(0) + Param(1);
    ftTriangleByHippuran:
      Result := Result + Param(0) + Param(2);

    ftCircleByLength:
      Result := Result + Param(5);
    ftCircleByRadius:
      Result := Result + Param(6);

    ftSectorByAngleAndRadius:
      Result := Result + Param(6) + Param(7);
    ftSegmentByChordAndLength:
      Result := Result + Param(0) + Param(5);
    ftSegmentByChordAndHeight:
      Result := Result + Param(0) + Param(4);
    ftContour:
      Result := Result + Param(7);
  end;
end;

function TsgAreaFigure.GetName: string;
begin
  if Length(FName) = 0 then
    Result := cnstAreaFigues[FType]
  else
    Result := FName;
end;

function TsgAreaFigure.GetPerimeter: Double;
var
  vRadius, vAngle: Double;
begin
  case FType of
    ftRect:
      Result := (A + B) * 2;
    ftSquare:
      Result := A * 4;
    ftRhomb:
      begin
        Result := Sqr(C) + Sqr(D);
        if Result > fAccuracy then
          Result := 2 * Sqrt(Result)
        else
          Result := 0
      end;
    ftTriangle:
      Result := A + B + C;
    ftTriangleRightAngled:
      begin
        Result := Sqr(A) + Sqr(B);
        if Result > fAccuracy then
          Result := A + B + Sqrt(Result)
        else
          Result := A + B;
      end;
    ftTriangleByHippuran:
      begin
        Result := Sqr(C) - Sqr(A);
        if Result > fAccuracy then
          Result := A + C + Sqrt(Result)
        else
          Result := C + A;
      end;
    ftCircleByLength:
      Result := L;
    ftCircleByRadius:
      Result := cnstPiMul2 * R;
    ftSectorByAngleAndRadius:
      Result := R * (A * fPiDividedBy180 + 2);
    ftSegmentByChordAndLength:
      Result := A + L;
    ftSegmentByChordAndHeight:
      begin
        Result := 0;
        if (A > fAccuracy) and (H > fAccuracy) then
        begin
          vRadius := GetRadiusByChordAndHeight(A, H);
          if vRadius > fAccuracy then
          begin
            vAngle := GetAngleByChordAndRadius(A, vRadius);
            Result := A + R * vAngle;
          end;
        end;
      end;
    ftContour:
      Result := P;
  else
    Result := 0;
  end;
  Result := FKoef * Result;
end;

function TsgAreaFigure.GetSign: Integer;
begin
  case FFlags and 3 of
    1:
      Result := -1;
    2:
      Result := +1;
  else
    Result := 0;
  end;
end;

procedure TsgAreaFigure.SetKoef(const Value: Double);
begin
  FKoef := Abs(Value);
end;

procedure TsgAreaFigure.SetSign(const Value: Integer);
begin
  FFlags := FFlags and 252;
  if Value > 0 then
    FFlags := FFlags or 2
  else if Value < 0 then
    FFlags := FFlags or 1;
end;

{ TsgExtendedBlockData }

procedure TsgExtendedBlockData.Assign(const Source: TsgExtendedBlockData);
type
  TsgTypeValue = (tvBoolean, tvByte, tvInteger, tvDouble, tvExtended,
    tvNativeUInt, tvF2DRect, tvColorCAD);

  procedure SetValue(var Pointer1, Pointer2: Pointer;
    const AType: TsgTypeValue);
  begin
    if Pointer2 <> nil then
    begin
      case AType of
        tvBoolean:
          begin
            if Pointer1 = nil then
              New(PBoolean(Pointer1));
            PBoolean(Pointer1)^ := PBoolean(Pointer2)^;
          end;
        tvByte:
          begin
            if Pointer1 = nil then
              New(PByte(Pointer1));
            PByte(Pointer1)^ := PByte(Pointer2)^;
          end;
        tvInteger:
          begin
            if Pointer1 = nil then
              New(PInteger(Pointer1));
            PInteger(Pointer1)^ := PInteger(Pointer2)^;
          end;
        tvDouble:
          begin
            if Pointer1 = nil then
              New(PDouble(Pointer1));
            PDouble(Pointer1)^ := PDouble(Pointer2)^;
          end;
        tvNativeUInt:
          begin
            if Pointer1 = nil then
              New(PsgNativeUInt(Pointer1));
            PsgNativeUInt(Pointer1)^ := PsgNativeUInt(Pointer2)^;
          end;
        tvF2DRect:
          begin
            if Pointer1 = nil then
              New(PF2DRect(Pointer1));
            PF2DRect(Pointer1)^ := PF2DRect(Pointer2)^;
          end;
        tvColorCAD:
          begin
            if Pointer1 = nil then
              New(PsgColorCAD(Pointer1));
            PsgColorCAD(Pointer1)^ := PsgColorCAD(Pointer2)^;
          end;
      else
        if Pointer1 = nil then
          New(PExtended(Pointer1));
        PExtended(Pointer1)^ := PExtended(Pointer2)^;
      end;
    end
    else if Pointer1 <> nil then
    begin
      Dispose(Pointer1);
      Pointer1 := nil;
    end;
  end;

  procedure AssignAttribs;
  var
    I: Integer;
    Psource, Pdest: PAttributeData;
  begin
    ClearAttribs;
    for I := 0 to Source.FAttribs.Count - 1 do
    begin
      Psource := Source.FAttribs[I];
      Pdest := nil;
      if Psource <> nil then
      begin
        New(Pdest);
        Pdest^.AttribType := Psource^.AttribType;
        Pdest^.Name := Psource^.Name;
        Pdest^.Value := Psource^.Value;
        Pdest^.Values := nil;
        case Pdest^.AttribType of
          atEnum:
            if Psource^.Values <> nil then
            begin
              Pdest^.Values := TStringList.Create;
              Pdest^.Values.Assign(Psource^.Values);
            end;
        end;
      end;
      FAttribs.Add(Pdest);
    end;
  end;

begin
  FFlags := Source.FFlags;
  SetValue(Pointer(FAlignment), Pointer(Source.FAlignment), tvBoolean);
  SetValue(Pointer(FCarvingMode), Pointer(Source.FCarvingMode), tvByte);
  SetValue(Pointer(FFillColor), Pointer(Source.FFillColor), tvColorCAD);
  LineType := Source.LineType;
  // SetValue(Pointer(FLineType), Pointer(Source.FLineType), tvNativeUInt);//By PPointer
  SetValue(Pointer(FIsCircular), Pointer(Source.FIsCircular), tvBoolean);
  SetValue(Pointer(FLength), Pointer(Source.FLength), tvDouble);
  SetValue(Pointer(FSegmentsCount), Pointer(Source.FSegmentsCount), tvInteger);
  SetValue(Pointer(FSegmentWidths), Pointer(Source.FSegmentWidths), tvF2DRect);
  SetValue(Pointer(FTypeSnapEntities), Pointer(Source.FTypeSnapEntities),
    tvInteger);
  SetValue(Pointer(FWidth), Pointer(Source.FWidth), tvDouble);
  SetValue(Pointer(FInsUnits), Pointer(Source.FInsUnits), tvByte);
  Parent := Source.Parent;
  FValueMask := Source.FValueMask;
  AssignAttribs;
end;

function TsgExtendedBlockData.GetXML: string;
var
  vXMLParser: TsgParser;
  FRootOut, vNode, vAttribut, vValues: TsgNode;
  I: Integer;
begin
  vXMLParser := TsgParser.Create;
  try
    FRootOut := TsgNode(vXMLParser.CreateRootNode.AddChildNV(cnstBTIExtData));
    FRootOut.AddAttribNV(cnstVersion).ValueData.ValueAsVersion :=
      MakeVersion(1, 0);

    FRootOut.AddChildNV(cnstBTIFlags).ValueAsInt := FFlags;
    FRootOut.AddChildNV(cnstBTIAlignment).ValueAsBool := Alignment;
    FRootOut.AddChildNV(cnstBTICarvingMode).ValueAsInt := CarvingMode;
    FRootOut.AddChildNV(cnstBTIFillColor).ValueData.ValueAsColor := FillColor;
    if LineType <> nil then
      FRootOut.AddChildNV(cnstBTILineType).ValueAsStr := LineType.Name
    else
      FRootOut.AddChildNV(cnstBTILineType).ValueAsStr := sContinuous;
    FRootOut.AddChildNV(cnstBTIIsCircular).ValueAsBool := IsCircular;
    FRootOut.AddChildNV(cnstBTILength).ValueAsDouble := Length;
    FRootOut.AddChildNV(cnstBTISegmentsCount).ValueAsInt := SegmentsCount;
    FRootOut.AddChildNV(cnstBTISegmentWidths).ValueAsF2DRect := SegmentWidths;
    FRootOut.AddChildNV(cnstBTITypeSnapEntities).ValueAsInt := TypeSnapEntities;
    FRootOut.AddChildNV(cnstBTIWidth).ValueAsDouble := Width;
    FRootOut.AddChildNV(cnstBTIInsUnits).ValueData.ValueAsByte :=
      Byte(InsUnits);
    if Assigned(Parent) then
      FRootOut.AddChildNV(cnstBTIParent).ValueAsStr := Parent.Name;
    FRootOut.AddChildNV(cnstBTIValueMask).ValueAsStr := ValueMask;

    if AttributesCount > 0 then
    begin
      vNode := FRootOut.AddChildNV(cnstBTIAttributes);
      for I := 0 to AttributesCount - 1 do
      begin
        vAttribut := vNode.AddChildNV(cnstBTIAttribut);
        vAttribut.AddAttribNV(cnstBTIName).ValueAsStr := Attributes[I].Name;
        vAttribut.AddAttribNV(cnstBTIValue).ValueAsStr := Attributes[I].Value;
        vAttribut.AddAttribNV(cnstBTIType).ValueAsInt :=
          Integer(Attributes[I].AttribType);
        if (Attributes[I].AttribType = atEnum) and Assigned(Attributes[I].Values)
        then
        begin
          vValues := vAttribut.AddChildNV(cnstBTIValues,
            Attributes[I].Values.Text);
          vValues.AddAttribNV(cnstBTIDelimiter, Attributes[I].Values.LineBreak);
        end;
      end;
    end;
    Result := vXMLParser.SaveToString;
  finally
    vXMLParser.Free;
  end;
end;

function TsgExtendedBlockData.SetXML(AXML: string;
  AConv: TsgDXFConverter): Boolean;
var
  vXMLParser: TsgParser;
  FRootOut: TsgNode;
  vAttributes, vNodeAttr, vValues, vNodeParent: TsgNodeSample;
  I: Integer;
  vType: Integer;
  vVersion: TsgVersion;
  vName, vValue: string;
  vValuesList: TStringList;
begin
  Result := False;
  vXMLParser := TsgParser.Create;
  try
    if not vXMLParser.LoadFromString(AXML) then
      Exit;
    FRootOut := TsgNode(vXMLParser.ROOT.NodeByName[cnstXML].GetChildByName
      (cnstBTIExtData));
    if Assigned(FRootOut) then
    begin
      vVersion := FRootOut.GetAttributeByName(cnstVersion)
        .ValueData.ValueAsVersion;
      if vVersion.Major = 1 then
      begin
        FFlags := FRootOut.GetChildByName(cnstBTIFlags).ValueAsInt;
        Alignment := FRootOut.GetChildByName(cnstBTIAlignment).ValueAsBool;
        CarvingMode := FRootOut.GetChildByName(cnstBTICarvingMode).ValueAsInt;
        FillColor := FRootOut.GetChildByName(cnstBTIFillColor).ValueAsInt;
        IsCircular := FRootOut.GetChildByName(cnstBTIIsCircular).ValueAsBool;
        Length := FRootOut.GetChildByName(cnstBTILength).ValueAsDouble;
        SegmentsCount := FRootOut.GetChildByName(cnstBTISegmentsCount)
          .ValueAsInt;
        SegmentWidths := FRootOut.GetChildByName(cnstBTISegmentWidths)
          .ValueAsF2DRect;

        TypeSnapEntities := FRootOut.GetChildByName(cnstBTITypeSnapEntities)
          .ValueAsInt;
        Width := FRootOut.GetChildByName(cnstBTIWidth).ValueAsDouble;
        ValueMask := FRootOut.GetChildByName(cnstBTIValueMask).ValueAsStr;
        InsUnits := TsgInsUnits(FRootOut.GetChildByName(cnstBTIInsUnits)
          .ValueData.ValueAsByte);
        vName := FRootOut.GetChildByName(cnstBTILineType).ValueAsStr;
        LineType := AConv.LTypeByName(vName);
        vNodeParent := FRootOut.GetChildByName(cnstBTIParent);
        if Assigned(vNodeParent) then
        begin
          vName := vNodeParent.ValueAsStr;
          Parent := AConv.BlockByName(vName);
        end;
        vAttributes := FRootOut.GetChildByName(cnstBTIAttributes);
        if Assigned(vAttributes) then
        begin
          vValuesList := nil;
          for I := 0 to vAttributes.ChildNodesCount - 1 do
          begin
            vNodeAttr := vAttributes.ChildNodes[I];
            vName := vNodeAttr.GetAttributeByName(cnstBTIName).ValueAsStr;
            vValue := vNodeAttr.GetAttributeByName(cnstBTIValue).ValueAsStr;
            vType := vNodeAttr.GetAttributeByName(cnstBTIType).ValueAsInt;
            vValues := vNodeAttr.GetChildByName(cnstBTIValues);
            vValuesList := TStringList.Create;
            if Assigned(vValues) then
            begin
              vValuesList := TStringList.Create;
              vValuesList.LineBreak := vValues.GetAttributeByName
                (cnstBTIDelimiter).ValueAsStr;
              vValuesList.Text := vValues.ValueAsStr;
            end;
            AddAttribute(vName, vValue, TsgAttribType(vType), vValuesList);
            FreeAndNil(vValuesList);
          end;
        end;
        Result := True;
      end;
    end;
  finally
    vXMLParser.Free;
  end;
end;

procedure TsgExtendedBlockData.AddAttribute(const AName, AValue: string;
  AType: TsgAttribType; ValuesList: TStringList = nil;
  const ASort: Boolean = False);
var
  AttrData: PAttributeData;
begin
  New(AttrData);
  try
    AttrData.AttribType := AType;
    AttrData.Name := AName;
    AttrData.Value := AValue;
    case AttrData.AttribType of
      atString:
        ;
      atEnum:
        if ValuesList <> nil then
        begin
          AttrData.Values := TStringList.Create;
          AttrData.Values.Assign(ValuesList);
          if ASort then
            AttrData.Values.Sort;
        end;
    end;
  finally
    FAttribs.Add(AttrData);
  end;
end;

procedure TsgExtendedBlockData.ClearAttribs;
begin
  while FAttribs.Count > 0 do
    DeleteAttribute(0);
end;

constructor TsgExtendedBlockData.Create;
begin
  inherited Create;
  FAttribs := TList.Create;
  FLineTypeItem := TsgTableItem.Create;
end;

procedure TsgExtendedBlockData.DeleteAttribute(AIndex: Integer);
var
  P: PAttributeData;
begin
  P := FAttribs[AIndex];
  FAttribs.Delete(AIndex);
  if P = nil then
    Exit;
  case P^.AttribType of
    atString:
      ;
    atEnum:
      P^.Values.Free;
  end;
  Dispose(P);
end;

destructor TsgExtendedBlockData.Destroy;
begin
  ClearAttribs;
  FAttribs.Free;
  DisposeAndNil(FCarvingMode);
  DisposeAndNil(FInsUnits);
  DisposeAndNil(FIsCircular);
  DisposeAndNil(FLength);
  DisposeAndNil(FSegmentsCount);
  DisposeAndNil(FSegmentWidths);
  DisposeAndNil(FTypeSnapEntities);
  DisposeAndNil(FWidth);
  DisposeAndNil(FFillColor);
  LineType := nil;
  FreeAndNil(FLineTypeItem);
  inherited Destroy;
end;

function TsgExtendedBlockData.GetAlignment: Boolean;
begin
  if FAlignment <> nil then
    Result := FAlignment^
  else if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
    Result := TsgExtendedBlockData(Parent.GetExtendedData).GetAlignment
  else
    Result := True;
end;

function TsgExtendedBlockData.GetArea: Boolean;
begin
  Result := FFlags in [cnstArea, cnstComplexArea];
end;

function TsgExtendedBlockData.GetAttribute(AIndex: Integer): TAttributeData;
begin
  Result := PAttributeData(FAttribs[AIndex])^;
end;

function TsgExtendedBlockData.GetAttributesCount: Integer;
begin
  Result := FAttribs.Count;
end;

function TsgExtendedBlockData.GetBroad: Boolean;
begin
  Result := FFlags in [cnstComplexBroad, cnstElementBroad, cnstElementCarved];
end;

function TsgExtendedBlockData.GetCarvingMode: Byte;
begin
  if FCarvingMode <> nil then
    Result := FCarvingMode^
  else if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
    Result := TsgExtendedBlockData(Parent.GetExtendedData).GetCarvingMode
  else
    Result := 2;
end;

function TsgExtendedBlockData.GetCircular: Boolean;
begin
  if FIsCircular <> nil then
    Result := FIsCircular^
  else if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
    Result := TsgExtendedBlockData(Parent.GetExtendedData).GetCircular
  else
    Result := False;
end;

function TsgExtendedBlockData.GetComplex: Boolean;
begin
  Result := FFlags in [cnstComplex, cnstComplexBroad, cnstComplexLinear,
    cnstComplexArea];
end;

function TsgExtendedBlockData.GetFillColor: TColor;
var
  vColorCAD: TsgColorCAD;
begin
  vColorCAD := GetFillColorCAD;
  if (vColorCAD.Active = acRGBColor) and (vColorCAD.Color = clEmpty) then
    Result := clEmpty
  else
    Result := ConvertColorCADToRGB(vColorCAD);
end;

function TsgExtendedBlockData.GetFillColorCAD: TsgColorCAD;
begin
  if FFillColor <> nil then
    Result := FFillColor^
  else if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
    Result := TsgExtendedBlockData(Parent.GetExtendedData).GetFillColorCAD
  else
    Result := MakeColorCAD(acRGBColor, clEmpty);
end;

function TsgExtendedBlockData.GetInsUnits: TsgInsUnits;
begin
  if FInsUnits <> nil then
    Result := TsgInsUnits(FInsUnits^)
  else if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
    Result := TsgExtendedBlockData(Parent.GetExtendedData).GetInsUnits
  else
    Result := TsgInsUnits(cnstSGHeadVarStruct.InsUnits);
end;

function TsgExtendedBlockData.GetLength: Double;
begin
  if FLength <> nil then
    Result := FLength^
  else if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
    Result := TsgExtendedBlockData(Parent.GetExtendedData).GetLength
  else
    Result := fAccuracy;
end;

function TsgExtendedBlockData.GetLineType: TsgDXFLineType;
begin
  if FLineTypeItem.Item <> nil then
    Result := TsgDXFLineType(FLineTypeItem.Item)
  else if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
    Result := TsgExtendedBlockData(Parent.GetExtendedData).GetLineType
  else
    Result := nil;
end;

function TsgExtendedBlockData.GetValueMask: string;
begin
  Result := FValueMask;
  if FValueMask = '' then
  begin
    if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
      Result := TsgExtendedBlockData(Parent.GetExtendedData).GetValueMask
    else
    begin
      case GetBTITypeByEntTypeEx(Flags) of
        btiArea, btiComplexArea:
          Result := cnstDefaultValueMask;
      end;
    end;
  end;
end;

function TsgExtendedBlockData.GetSegmentsCount: Integer;
begin
  if FSegmentsCount <> nil then
    Result := FSegmentsCount^
  else if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
    Result := TsgExtendedBlockData(Parent.GetExtendedData).GetSegmentsCount
  else
    Result := 0;
end;

function TsgExtendedBlockData.GetSegmentWidths: TF2DRect;
var
  W: Double;
begin
  if FSegmentWidths <> nil then
    Result := FSegmentWidths^
  else if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
    Result := TsgExtendedBlockData(Parent.GetExtendedData).GetSegmentWidths
  else
  begin
    W := Width * 0.5;
    Result := MakeF2DRect(W, W, W, W);
  end;
end;

function TsgExtendedBlockData.GetSize: TF2DPoint;
begin
  Result.X := Length;
  Result.Y := Width;
end;

function TsgExtendedBlockData.GetTypeSnapEntities: Integer;
begin
  if FTypeSnapEntities <> nil then
    Result := FTypeSnapEntities^
  else if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
    Result := TsgExtendedBlockData(Parent.GetExtendedData).GetTypeSnapEntities
  else
    Result := -1;
end;

function TsgExtendedBlockData.GetWidth: Double;
begin
  if FWidth <> nil then
    Result := FWidth^
  else if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
    Result := TsgExtendedBlockData(Parent.GetExtendedData).GetWidth
  else
    Result := fAccuracy;
end;

function TsgExtendedBlockData.HasSegmentWidths: Boolean;
begin
  if FSegmentWidths <> nil then
    Result := True
  else if (Parent <> nil) and (Parent.GetExtendedData <> nil) then
    Result := TsgExtendedBlockData(Parent.GetExtendedData).HasSegmentWidths
  else
    Result := False;
end;

procedure TsgExtendedBlockData.SetAlignment(const Value: Boolean);
begin
  if FAlignment = nil then
    New(FAlignment);
  FAlignment^ := Value;
end;

procedure TsgExtendedBlockData.SetAttribute(AIndex: Integer;
  const Value: TAttributeData);
begin
  PAttributeData(FAttribs[AIndex])^ := Value;
end;

procedure TsgExtendedBlockData.SetCarvingMode(const Value: Byte);
begin
  if FCarvingMode = nil then
    New(FCarvingMode);
  FCarvingMode^ := Value
end;

procedure TsgExtendedBlockData.SetCircular(const Value: Boolean);
begin
  if FIsCircular = nil then
    New(FIsCircular);
  FIsCircular^ := Value;
end;

procedure TsgExtendedBlockData.SetFillColor(const Value: TColor);
begin
  if Value = clEmpty then
    SetFillColorCAD(MakeColorCAD(acRGBColor, clEmpty))
  else
    SetFillColorCAD(ConvertColortoColorCAD(Value));
end;

procedure TsgExtendedBlockData.SetFillColorCAD(const Value: TsgColorCAD);
begin
  if FFillColor = nil then
    New(FFillColor);
  FFillColor^ := Value;
end;

procedure TsgExtendedBlockData.SetInsUnits(const Value: TsgInsUnits);
begin
  if FInsUnits = nil then
    New(FInsUnits);
  FInsUnits^ := Byte(Value);
end;

procedure TsgExtendedBlockData.SetLength(const Value: Double);
begin
  if FLength = nil then
    New(FLength);
  FLength^ := Value;
end;

procedure TsgExtendedBlockData.SetLineType(const Value: TsgDXFLineType);
begin
  FLineTypeItem.Item := Value;
end;

procedure TsgExtendedBlockData.SetValueMask(const Value: string);
begin
  FValueMask := Value;
end;

procedure TsgExtendedBlockData.SetSegmentsCount(const Value: Integer);
begin
  if FSegmentsCount = nil then
    New(FSegmentsCount);
  FSegmentsCount^ := Value;
  if FSegmentsCount^ < 1 then
    DisposeAndNil(FSegmentWidths);
end;

procedure TsgExtendedBlockData.SetSegmentWidths(const Value: TF2DRect);
begin
  if FSegmentWidths = nil then
    New(FSegmentWidths);
  FSegmentWidths^ := Value;
end;

procedure TsgExtendedBlockData.SetSize(const Value: TF2DPoint);
begin
  Length := Value.X;
  Width := Value.Y;
end;

procedure TsgExtendedBlockData.SetParent(const AValue: TsgDXFBlock);
begin
  FParent := AValue;
end;

procedure TsgExtendedBlockData.SetTypeSnapEntities(const Value: Integer);
begin
  if FTypeSnapEntities = nil then
    New(FTypeSnapEntities);
  FTypeSnapEntities^ := Value;
end;

procedure TsgExtendedBlockData.SetWidth(const Value: Double);
begin
  if FWidth = nil then
    New(FWidth);
  FWidth^ := Value;
end;

{$ENDIF}
{ TsgMLineStyle }

constructor TsgMLineStyle.Create;
begin
  inherited Create;
  FEntries := TListNotify(TListNotify.CreateList(ListNotify));
end;

procedure TsgMLineStyle.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FEntries);
end;

procedure TsgMLineStyle.Clear(const ADoFree: Boolean);
begin
  inherited Clear(ADoFree);
  ClearEntCollection(FEntries, ADoFree);
end;

function TsgMLineStyle.GetCount: Integer;
begin
  Result := FEntries.Count;
end;

function TsgMLineStyle.GetEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := GetEntry(AIndex);
end;

function TsgMLineStyle.GetEntry(Index: Integer): TsgMLineEntry;
begin
  Result := TsgMLineEntry(FEntries[Index]);
end;

procedure TsgMLineStyle.NewEntry(AOffset: Double; AColor: TsgColorCAD;
  ALType: TsgDXFLineType);
var
  M: TsgMLineEntry;
begin
  M := TsgMLineEntry.Create;
  M.Offset := AOffset;
  M.ColorCAD := AColor;
  M.LineType := ALType;
  FEntries.Add(M);
end;

function TsgMLineStyle.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  Result := AEntity is TsgMLineEntry;
  if Result then
    FEntries.Insert(AIndex, AEntity);
end;

procedure TsgMLineStyle.AssignEntity(Source: TsgDXFEntity);
var
  M: TsgMLineStyle absolute Source;
  E: TsgMLineEntry;
  I: Integer;
begin
  inherited AssignEntity(Source);
  if Source is TsgMLineStyle then
  begin
    Flags := M.Flags;
    Clear;
    for I := 0 to M.Count - 1 do
    begin
      E := M[I];
      NewEntry(E.Offset, E.ColorCAD, E.LineType);
    end;
  end;
end;

{ TsgMVertex }

constructor TsgMVertex.Create;
begin
  inherited Create;
  FParams := TList.Create;
end;

procedure TsgMVertex.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FParams);
end;

function TsgMVertex.GetPCount(Index: Integer): Integer;
begin
  Result := TsgSingleList(FParams[Index]).Count;
end;

function TsgMVertex.GetParam(I1, I2: Integer): Single;
begin
  Result := TsgSingleList(FParams[I1])[I2];
end;

function TsgMVertex.GetParamsCount: Integer;
begin
  Result := FParams.Count;
end;

function TsgMVertex.GetParamsList: TList;
begin
  Result := FParams;
end;

procedure TsgMVertex.SetParam(I1, I2: Integer; Value: Single);
begin
  TsgSingleList(FParams[I1])[I2] := Value;
end;

procedure TsgMVertex.Add(Value: Single);
begin
  TsgSingleList(FParams.Last).Add(Value);
end;

procedure TsgMVertex.ClearReferences;
begin
  inherited ClearReferences;
  ClearList(FParams);
end;

procedure TsgMVertex.Complete;
var
  L: TsgSingleList;
begin
  if FParams.Count = 0 then
    Exit;
  L := TsgSingleList(FParams.Last);
  while L.Count < 2 do
    L.Add(0);
end;

procedure TsgMVertex.NewList;
begin
  Complete;
  FParams.Add(TsgSingleList.Create);
end;

procedure TsgMVertex.AssignEntity(Source: TsgDXFEntity);
var
  V: TsgMVertex absolute Source;
  I: Integer;
  vDst, vSrc: TsgSingleList;
begin
  inherited AssignEntity(Source);
  if Source is TsgMVertex then
  begin
    Point := V.Point;
    Miter := V.Miter;
    Direction := V.Direction;
    ClearList(FParams);
    for I := 0 to V.ParamsCount - 1 do
    begin
      vSrc := V.ParamsList[I];
      vDst := TsgSingleList.Create;
      vDst.Assign(vSrc);
      ParamsList.Add(vDst);
    end;
  end;
end;

{ TsgCADMLine }

procedure TsgCADMLine.Clear(const ADoFree: Boolean);
begin
  inherited Clear(ADoFree);
  ClearEntCollection(FItems, ADoFree);
end;

procedure TsgCADMLine.CopyItems(const ASource: TsgDXFEntity);
var
  vSrc, vDst: TsgDXFEntity;
  I: Integer;
begin
  inherited CopyItems(ASource);
  for I := 0 to TsgCADMLine(ASource).ItemsCount - 1 do
  begin
    vSrc := TsgCADMLine(ASource).Items[I];
    vDst := TsgDXFEntityClass(vSrc.ClassType).Create;
    vDst.AssignEntity(vSrc);
    FItems.Add(vDst);
  end;
end;

constructor TsgCADMLine.Create;
begin
  inherited Create;
  FLineTypeScale := 1;
  FStartPoint := cnstFPointZero;
  FItems := TListNotify(TListNotify.CreateList(ListNotify));
  Block := TsgDXFBlock.Create;
end;

function TsgCADMLine.GetCount: Integer;
begin
  Result := GetItemsCount;
end;

function TsgCADMLine.GetItemsCount: Integer;
begin
  Result := FItems.Count;
end;

function TsgCADMLine.GetJustify: Byte;
begin
  Result := FJustify;
end;

function TsgCADMLine.GetEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := GetItem(AIndex);
end;

function TsgCADMLine.GetEntType: TsgCADEntities;
begin
  Result := ceMLine;
end;

function TsgCADMLine.GetItem(Index: Integer): TsgMVertex;
begin
  Result := TsgMVertex(FItems[Index]);
end;

function TsgCADMLine.GetScaleFactor: Double;
begin
  Result := FScaleFactor;
end;

function TsgCADMLine.GetStyle: TsgMLineStyle;
begin
  Result := FStyle;
end;

function TsgCADMLine.GetFlags: Integer;
begin
  Result := FFlags;
end;

function TsgCADMLine.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  Result := AEntity is TsgMVertex;
  if Result then
    FItems.Insert(AIndex, AEntity);
end;

procedure TsgCADMLine.SetPoint(AValue: TFPoint);
begin
  // do not Offset MLINE
end;

procedure TsgCADMLine.SetScaleFactor(const Value: Double);
begin
  FScaleFactor := Value;
end;

procedure TsgCADMLine.SetStyle(const Value: TsgMLineStyle);
begin
  FStyle := Value;
end;

function TsgCADMLine.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlJustify].Name).ValueAsInt := FJustify;
end;

procedure TsgCADMLine.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FItems);
end;

function TsgCADMLine.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlJustify:
      FJustify := ANode.ValueAsInt;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure TsgCADMLine.SetFlags(const Value: Integer);
begin
  FFlags := Value;
end;

procedure TsgCADMLine.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(Style) and (Style.ClassType = TsgLinkObject) then
    Style := TsgMLineStyle(TsgLinkObject(Style)
      .GetObject(AConverter.Sections[csMLineStyles]));
end;

procedure TsgCADMLine.LoadedInternal(AConverter: TsgDXFConverter);
var
  I, J, K, Cnt: Integer;
  PL: TsgDXFPolyline;
  MV: TsgMVertex;
  V: TsgDXFVertex;
  P: TFPoint;

  procedure NewPL;
  begin
    PL := TsgDXFPolyline.Create;
    Block.AddEntity(PL);
    PL.ColorCAD := FStyle[I].ColorCAD;
    PL.LineType := FStyle[I].LineType;
    PL.Layer := Layer;
    PL.Extrusion := Extrusion;
    PL.LineTypeScale := LineTypeScale;
    PL.LineWeight := LineWeight;
    PL.Closed := FFlags and 2 <> 0;
    PL.SetPLineGen(True);
    PL.Polyline3D := True;
  end;
  procedure EndPL;
  begin
    PL.Loaded(AConverter);
  end;
  function vPoint(const P1, P2: TFPoint; Scale: Double): TFPoint;
  begin
    Result.X := P1.X + Scale * P2.X;
    Result.Y := P1.Y + Scale * P2.Y;
    Result.Z := P1.Z + Scale * P2.Z;
  end;

begin
  if FStyle = nil then
    Exit;
  // Take the value up the stack
  if not Assigned(LineType) then
    LineType := TsgDXFLineType(AConverter.CustomEntByName(sByBlock, csLTypes));
  ColorCAD := MakeColorCAD(acIndexColor, clDXFByBlock);
  Block.Clear(True);
  for I := 0 to FStyle.Count - 1 do
  begin
    NewPL;
    for J := 0 to ItemsCount - 1 do
    begin
      MV := Items[J];
      Cnt := MV.PCounts[I] - 1;
      P := vPoint(MV.FPoint, MV.FMiter, MV[I, 0]);
      for K := 1 to Cnt do
      begin
        V := TsgDXFVertex.Create;
        V.FPoint := vPoint(P, MV.FDirection, MV[I, K]);
        PL.AddEntity(V);
        if K = Cnt then
          Break;
        if K and 1 <> 0 then
          Continue;
        EndPL;
        NewPL;
      end;
    end;
    EndPL;
  end;
  if FStyle.FFlags and 1 <> 0 then
  begin
    SetFill;
    Block.Entities[0].Loaded(AConverter);
  end;
  inherited LoadedInternal(AConverter);
end;

procedure TsgCADMLine.ReferenceBlockRecord(ABlockRecord: TsgDXFBlockRecord);
begin
  // do nothing, MLine must use only self block
end;

procedure TsgCADMLine.SetEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity);
begin
  FItems[AIndex] := AEntity;
end;

procedure TsgCADMLine.SetFill;
var
  FFill: TsgCADPolyPolygon;
  I, J: Integer;
  vPoints: TF2DPointList;
  MV: TsgMVertex;
  vPoint2D: TF2DPoint;
  PC, PMax, PMin: Single;
begin
  FFill := TsgCADPolyPolygon.Create;
  Block.InsertEntity(0, FFill);
  FFill.ColorCAD := FStyle.ColorCAD;
  vPoints := TF2DPointList.Create;
  FFill.Boundaries.Add(vPoints);
  for I := 0 to ItemsCount - 1 do
  begin
    MV := Items[I];
    if MV.ParamsCount = 0 then
      Continue;
    PMax := -1E30;
    PMin := 1E30;
    for J := 0 to MV.ParamsCount - 1 do
    begin
      PC := MV[J, 0];
      if PMax < PC then
        PMax := PC;
      if PMin > PC then
        PMin := PC;
    end;
    vPoint2D.X := MV.FPoint.X + PMax * MV.FMiter.X;
    vPoint2D.Y := MV.FPoint.Y + PMax * MV.FMiter.Y;
    vPoints.Insert(I, vPoint2D);
    vPoint2D.X := MV.FPoint.X + PMin * MV.FMiter.X;
    vPoint2D.Y := MV.FPoint.Y + PMin * MV.FMiter.Y;
    vPoints.Insert(I + 1, vPoint2D);
  end;
end;

procedure TsgCADMLine.SetJustify(const Value: Byte);
begin
  FJustify := Value;
end;

procedure TsgCADMLine.AssignEntity(Source: TsgDXFEntity);
var
  M: TsgCADMLine absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgCADMLine then
  begin
    Style := M.Style;
    Flags := M.Flags;
    Justify := M.Justify;
  end;
end;

{ TsgCADHelix }

procedure TsgCADHelix.AssignEntity(Source: TsgDXFEntity);
var
  H: TsgCADHelix absolute Source;
begin
  inherited AssignEntity(Source);
  if not(Source is TsgCADHelix) then
    Exit;
  Start := H.Start;
  Radius := H.Radius;
  Turns := H.Turns;
  TurnHeight := H.TurnHeight;
  Clockwise := H.Clockwise;
end;

function TsgCADHelix.GetEntType: TsgCADEntities;
begin
  Result := ceHelix;
end;

procedure TsgCADHelix.LoadedInternal(AConverter: TsgDXFConverter);
var
  A, R, DA, DR, DZ: Double;
  S, C: Extended;
  N: Integer;
  P: TFPoint;
  // Knot: Single;
begin
  Controls.Clear(False);
  Fit.Clear(False);
  Knots.Clear(False);
  P.X := Start.X - Point.X;
  P.Y := Start.Y - Point.Y;
  P.Z := Start.Z;
  R := Sqrt(P.X * P.X + P.Y * P.Y);
  A := ArcTan2(P.Y, P.X);
  N := Ceil(16 * Turns);
  DR := (Radius - R) / N;
  DZ := Turns * TurnHeight / N;
  DA := 2 * Pi * Turns / N;
  if Clockwise then
    DA := -DA;
  while N >= 0 do
  begin
    SinCos(A, S, C);
    P.X := Point.X + R * C;
    P.Y := Point.Y + R * S;
    Fit { Controls }.Add(P);
    A := A + DA;
    R := R + DR;
    P.Z := P.Z + DZ;
    Dec(N);
  end;
  (* Knot := 0.0;
    FKnots.Add(Pointer(Knot));
    FKnots.Add(Pointer(Knot));
    for I := 1 to FControls.Count-1 do
    begin      // Knots
    Knot := Knot + DistanceF(PFPoint(FControls[I])^, PFPoint(FControls[I-1])^);
    FKnots.Add(Pointer(Knot));
    end;
    FKnots.Add(Pointer(Knot));
    FKnots.Add(Pointer(Knot));
    FKnots.Add(Pointer(Knot)); *)
  inherited LoadedInternal(AConverter);
end;

function TsgCADHelix.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlStart].Name).ValueAsFPoint := Start;
  ANode.AddAttribNV(cnstXMLNames[xmlRadius].Name).ValueAsDouble := Radius;
  ANode.AddAttribNV(cnstXMLNames[xmlTurns].Name).ValueAsDouble := Turns;
  ANode.AddAttribNV(cnstXMLNames[xmlTurnHeight].Name).ValueAsDouble :=
    TurnHeight;
  ANode.AddAttribNV(cnstXMLNames[xmlClockwise].Name).ValueAsBool := Clockwise;
end;

function TsgCADHelix.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlStart:
      Start := ANode.ValueAsFPoint;
    xmlRadius:
      Radius := ANode.ValueAsDouble;
    xmlTurns:
      Turns := ANode.ValueAsDouble;
    xmlTurnHeight:
      TurnHeight := ANode.ValueAsDouble;
    xmlClockwise:
      Clockwise := ANode.ValueAsBool;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

{ TBufferedStream }

constructor TBufferedStream.Create(AStream: TStream; ABufSize: Integer);
begin
  FStream := AStream;
  FBufSize := 4096;
  while FBufSize < ABufSize do
    Inc(FBufSize, FBufSize);
  GetMem(FBuffer, FBufSize);
  FBufPtr := FBuffer;
  FBufEnd := FBuffer;
end;

destructor TBufferedStream.Destroy;
begin
  Overflow;
  FreeMem(FBuffer);
  inherited Destroy;
end;

function TBufferedStream.Overflow: Boolean;
var
  N: TsgNativeInt;
begin
  N := TsgNativeInt(FBufPtr) - TsgNativeInt(FBufEnd);
  Result := (N <= 0) or (N = FStream.Write(FBufEnd^, N));
  FBufPtr := FBuffer;
  FBufEnd := FBuffer;
end;

function TBufferedStream.Underflow: Boolean;
begin
  Overflow;
  FBufEnd := FBuffer + FStream.Read(FBuffer^, FBufSize);
  Result := FBufEnd > FBuffer;
end;

function TBufferedStream.GetByte(var Buffer): Boolean;
begin
  Result := (FBufPtr < FBufEnd) or Underflow;
  if not Result then
    Exit;
  PAnsiChar(@Buffer)^ := FBufPtr^;
  Inc(FBufPtr);
end;

function TBufferedStream.PutByte(const Buffer): Boolean;
begin
  Result := (FBufPtr < FBuffer + FBufSize) or Overflow;
  if not Result then
    Exit;
  FBufPtr^ := PAnsiChar(@Buffer)^;
  Inc(FBufPtr);
end;

{$IFNDEF SGDEL_6}

function TBufferedStream.Seek(Offset: Longint; Origin: Word): Longint;
{$ELSE}

function TBufferedStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
{$ENDIF}
begin
  Overflow;
  Result := FStream.Seek(Offset, Origin);
end;

function TBufferedStream.Read(var Buffer; Count: Integer): Longint;
var
  P: PAnsiChar;
begin
  P := PAnsiChar(@Buffer);
  Result := 0;
  while (Count > 0) and GetByte(P^) do
  begin
    Inc(P);
    Inc(Result);
    Dec(Count);
  end;
end;

function TBufferedStream.Write(const Buffer; Count: Integer): Longint;
var
  P: PAnsiChar;
begin
  P := PAnsiChar(@Buffer);
  Result := 0;
  while (Count > 0) and PutByte(P^) do
  begin
    Inc(P);
    Inc(Result);
    Dec(Count);
  end;
end;

function CompareRegClass(Self: Pointer; const Value1, Value2: Pointer): Integer;
begin
  Result := PsgRegClass(Value1)^.RID - PsgRegClass(Value2)^.RID;
end;

procedure ExternalEntitiesCreate;
begin
  if ExternalEntities <> nil then
    Exit;
  ExternalEntities := TsgStringList.Create;
  ExternalEntities.Duplicates := dupIgnore;
  ExternalEntities.Sorted := True;
  ExternalEntities.CaseSensitive := False;
end;

procedure ExternalEntitiesFree;
var
  I: Integer;
  vClasses: TsgList;
begin
  if ExternalEntities = nil then
    Exit;
  for I := 0 to ExternalEntities.Count - 1 do
  begin
    vClasses := TsgList(ExternalEntities.Objects[I]);
    if vClasses <> nil then
    begin
      ExternalEntities.Objects[I] := nil;;
      vClasses.ClearTypeList(ptvRecord);
      vClasses.Free;
    end;
  end;
  ExternalEntities.Free;
  ExternalEntities := nil;
end;

function CreateRegEntity(const AGroup: string; const ID: Integer;
  const AConv: TsgDXFConverter; var AExtData: TsgCADExtendedData): TsgDXFEntity;
var
  I: Integer;
  vClass: TClass;
  vClasses: TsgList;
  vRegClass: TsgRegClass;
begin
  Result := nil;
  if ExternalEntities = nil then
    Exit;
  I := ExternalEntities.IndexOf(AGroup);
  if I > -1 then
  begin
    vRegClass.RID := ID;
    vClasses := TsgList(ExternalEntities.Objects[I]);
    I := vClasses.IndexOf(@vRegClass);
    if I > -1 then
    begin
      vClass := PsgRegClass(vClasses.Items[I])^.RClass;
      Result := TsgDXFEntityClass(vClass).Create;
      Result.SetConverter(AConv);
      Result.SetExtData(AExtData);
    end;
  end;
end;

procedure RegisterEntityClass(const AGroup: string; const ID: Integer;
  const AClass: TClass);
var
  I: Integer;
  vClasses: TsgList;
  vProcCompare: Pointer;
  vObjProcCompare: TsgObjProcCompare absolute vProcCompare;
  vRegClass: PsgRegClass;
begin
  if ExternalEntities = nil then
    ExternalEntitiesCreate;
  I := ExternalEntities.IndexOf(AGroup);
  if I > -1 then
    vClasses := TsgList(ExternalEntities.Objects[I])
  else
  begin
    vProcCompare := @CompareRegClass;
    vClasses := TsgList.Create;
    ExternalEntities.AddObject(AGroup, vClasses);
    vClasses.ProcCompare := vObjProcCompare;
    vClasses.Duplicates := dupIgnore;
    vClasses.Sorted := True;
  end;
  I := vClasses.Count;
  New(vRegClass);
  try
    vRegClass^.RID := ID;
    vRegClass^.RClass := AClass;
    vClasses.Add(vRegClass);
  finally
    if vClasses.Count = I then
      Dispose(vRegClass);
  end;
end;

procedure UnRegisterEntityClass(const AGroup: string; const ID: Integer);
var
  I, J: Integer;
  vClasses: TsgList;
  vRegClass: TsgRegClass;
begin
  if ExternalEntities = nil then
    Exit;
  I := ExternalEntities.IndexOf(AGroup);
  if I > -1 then
  begin
    vRegClass.RID := ID;
    vClasses := TsgList(ExternalEntities.Objects[I]);
    J := vClasses.IndexOf(@vRegClass);
    if J > -1 then
    begin
      vClasses.Delete(J);
      if vClasses.Count = 0 then
      begin
        ExternalEntities.Objects[I] := nil;
        vClasses.Free;
        ExternalEntities.Delete(I);
        if ExternalEntities.Count = 0 then
        begin
          ExternalEntities.Free;
          ExternalEntities := nil;
        end;
      end;
    end;
  end;
end;

{ TsgDXFSurface }

function TsgDXFSurface.GetEntType: TsgCADEntities;
begin
  Result := ceSurface;
end;

{ TsgMLineEntry }

procedure TsgMLineEntry.ClearReferences;
begin
  inherited ClearReferences;
  FLineTypeItem.Item := nil;
end;

constructor TsgMLineEntry.Create;
begin
  inherited Create;
  FLineTypeItem := TsgTableItem.Create;
end;

procedure TsgMLineEntry.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FLineTypeItem);
end;

function TsgMLineEntry.GetColorCAD: TsgColorCAD;
begin
  Result := FColor;
end;

function TsgMLineEntry.GetLineType: TsgDXFLineType;
begin
  Result := TsgDXFLineType(FLineTypeItem.Item);
end;

procedure TsgMLineEntry.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  if Assigned(LineType) and (LineType.ClassType = TsgLinkObject) then
    LineType := TsgDXFLineType(TsgLinkObject(LineType)
      .GetObject(AConverter.Sections[csLTypes]));
end;

procedure TsgMLineEntry.SetColorCAD(const Value: TsgColorCAD);
begin
  FColor := Value;
end;

procedure TsgMLineEntry.SetLineType(const AValue: TsgDXFLineType);
begin
  FLineTypeItem.Item := AValue;
end;

{ TsgCreatorSegments }

procedure TsgCreatorSegments.MakeSegments(const APoints: TFPointList;
  const ACenter: PFPoint);
var
  I, vPointsCount: Integer;
  vStartWidth, vEndWidth, vDeltaWidth: Double;
  vP0, vP1, vP2: TFPoint;
  vPts, vPtsCurrent, vPtsFirst: TsgIndexes4;
  vPtsLinear: Boolean;
begin
  vPtsLinear := ACenter = nil;
  vPts := cnstIndexesNoInit;
  vPtsCurrent := vPts;
  vPtsFirst := vPts;
  vP0 := APoints[0];
  I := 0;
  vPointsCount := APoints.Count - 1; // for pre last
  if UseAsSolid then
    vDeltaWidth := (FEndWidth - FStartWidth) / vPointsCount
  else
  begin
    if FSegmentLength <> 0 then
      vDeltaWidth := (FEndWidth - FStartWidth) / FSegmentLength
    else
      vDeltaWidth := 0;
  end;
  while I < vPointsCount do
  begin
    vP1 := APoints.List[I];
    vP2 := APoints.List[I + 1];
    if UseAsSolid then
    begin
      vStartWidth := FStartWidth + I * vDeltaWidth;
      vEndWidth := FStartWidth + (I + 1) * vDeltaWidth;
    end
    else
    begin
      vStartWidth := FStartWidth + DistanceFPoint(vP0, vP1) * vDeltaWidth;
      vEndWidth := FStartWidth + DistanceFPoint(vP0, vP2) * vDeltaWidth;
    end;
    Inc(I, 1 + Integer(not UseAsSolid)); // make empty dash
    vPts := AddSegment(ACenter, @vP1, @vP2, vStartWidth, vEndWidth);
    if (not FIsPolyLineSolid) or (vPointsCount = 1) or
      (vPts[0] > cnstEmptyPoints) then
    begin
      vPtsCurrent := vPts;
      if vPtsFirst[0] = cnstNoInitPoints then
        vPtsFirst := vPtsCurrent;
    end;
  end;
  if FIsPolyLineSolid or FMakeCrossSegments then
    CrossingSegments(FSegmentLastLinear, vPtsLinear, FSegmentLast, vPtsFirst);
  FSegmentLast := vPtsCurrent;
  FSegmentLastLinear := vPtsLinear;
  if FSegmentFirst[0] = cnstNoInitPoints then
  begin
    FSegmentFirst := vPtsFirst;
    FSegmentFirstLinear := vPtsLinear;
  end;
end;

procedure TsgCreatorSegments.LoadPoinstBySegment(const AClosed: Boolean;
  const ACenter: PFPoint);
var
  vScale: TFPoint;
begin
  try
    LoadPointsAndCalcParams;
    if UseAsSolid then
      MakeSegments(FPoints, ACenter)
    else
    begin
      if FDottedSingPts = nil then
      begin
        FDottedSingPts := TFPointList.Create;
        FCounts := TsgIntegerList.Create;
      end;
      FDottedSingPts.Clear(False);
      FCounts.Count := 1;
      FCounts[0] := FPoints.Count;
      if Assigned(FMatrix) then
      begin
        vScale := ExtractMatrixAbsoluteScale(FMatrix^);
        ScaleList(FPoints, vScale);
      end;
      FPolyLine.FArrowsLines.Vertexes(FPoints, FCounts, FDottedSingPts, False);
      if Assigned(FMatrix) then
      begin
        vScale := ReverseScale(vScale);
        ScaleList(FPoints, vScale);
        ScaleList(FDottedSingPts, vScale);
      end;
      if (FDottedSingPts.Count <= iMaxNumDottedLines) and
        (FDottedSingPts.Count <> 0) then
        MakeSegments(FDottedSingPts, ACenter)
      else
      begin
        FIsManyDottedPoints := True;
        FreeAndNil(FDottedSingPts);
        FreeAndNil(FCounts);
        MakeSegments(FPoints, ACenter);
      end;
    end;
    if FIsPolyLineSolid and AClosed then
      CrossingSegments(FSegmentLastLinear, FSegmentFirstLinear, FSegmentLast,
        FSegmentFirst);
  finally
    ClearPFPoints;
  end;
end;

procedure TsgCreatorSegments.LoadPointsAndCalcParams;
var
  vPoint1, vPoint2: PFPoint;
  I: Integer;
begin
  vPoint2 := nil;
  FSegmentLength := 0;
  for I := 1 to FPointsCount do
  begin
    vPoint1 := GetPFPoint(FPolyPoints, FPointsIndex);
    if vPoint2 <> nil then
      FSegmentLength := FSegmentLength + DistanceFPoint(vPoint1^, vPoint2^);
    AddPFPoint(vPoint1);
    Inc(FPointsIndex);
    vPoint2 := vPoint1;
  end;
  vPoint1 := GetPFPoint(FPolyPoints, FPointsIndex);
  AddPFPoint(vPoint1);
  if vPoint2 <> nil then
    FSegmentLength := FSegmentLength + DistanceFPoint(vPoint1^, vPoint2^);
  if FPoints.Count = 2 then
  begin
    FSegmentSinCos := GetFPointSinCosByFPoints(FPoints.List[0],
      FPoints.List[1]);
    FPointSinCosRot90(FSegmentSinCos);
  end
  else
    FSegmentSinCos := cnstFPointZero;
end;

procedure TsgCreatorSegments.AddPFPoint(const APoint: PFPoint);
begin
  if FPolyExtrusion <> nil then
  begin
    FPoints.Add(APoint^);
    DoPreExtrusion(FPoints.List^[FPoints.Count - 1], FPolyExtrusion^);
  end
  else
    FPoints.Add(APoint^);
end;

function TsgCreatorSegments.AddSegment(const APC, AP1, AP2: PFPoint;
  const AW1, AW2: Double): TsgIndexes4;
var
  I: Integer;
  vSegment: TsgPoints4;
begin
  Result := cnstIndexesEmpty;
  if FIsPolyLineSolid and IsEqualFPoints(AP1^, AP2^) then // ignore point
  begin
    if APC = nil then // fix in future version
    begin
      // FillChar(Result, Sizeof(Result), 0)
    end;
  end
  else
  begin
    if APC = nil then
      vSegment := GetSegmentLinear(AP1^, AP2^, AW1, AW2)
    else
      vSegment := GetSegmentCircular(APC^, AP1^, AP2^, AW1, AW2);
    for I := 0 to 3 do
    begin
      FArrows.Add(vSegment[I]);
      Result[I] := FPolyLine.FArrows.Count - 1;
    end;
  end;
end;

procedure TsgCreatorSegments.CheckGlobalWidth;
var
  I: Integer;
  vGlobalWdt: Boolean;
  vVertex: TsgDXFVertex;
  vStartWidth: Double;
begin
  if (VertexesCount > 0) and (Vertexes[0].StartWidth > 0) then
  begin
    vGlobalWdt := True;
    vStartWidth := Vertexes[0].StartWidth;
    vVertex := nil;
    for I := 0 to VertexesCount - 2 do
    begin
      vVertex := Vertexes[I];
      vGlobalWdt := (vVertex.StartWidth = vVertex.EndWidth) and
        (vVertex.StartWidth = vStartWidth) and vGlobalWdt;
      vStartWidth := vVertex.StartWidth;
      if not vGlobalWdt then
        Break;
    end;
    if vGlobalWdt and (vVertex <> nil) then
      FPolyLine.FGlobalW := vVertex.StartWidth;
  end
  else if FPolyLine.FGlobalW = 0 then
    FPolyLine.FGlobalW := FPolyLine.FStartW;
end;

procedure TsgCreatorSegments.ClearPFPoints;
begin
  if FPolyExtrusion <> nil then
    FPoints.Clear(False)
  else
    FPoints.Count := 0;
end;

constructor TsgCreatorSegments.Create(const APolyline: TsgDXFLWPolyline;
  const ALines: TsgLines; const AMatrix: PFMatrix);
begin
  inherited Create;
  FMatrix := AMatrix;
  FPoints := TFPointList.Create;
  FIsPolyLineSolid := True;
  FIsPolylineClosed := False;
  FPolyExtrusion := nil;
  FPolyLine := APolyline;
  if FPolyLine <> nil then
  begin
    FPolyPoints := FPolyLine.FPolyPoints;
    FPolyCounts := FPolyLine.FPointsCounts;
    FIsPolylineClosed := FPolyLine.Closed;
    FMakeCrossSegments := FPolyLine.IsPathEvacuation;
    FPolyExtrusion := FPolyLine.FExtrusion;
    FPolyLine.FArrowsLines := ALines;
    if Assigned(FPolyLine.FArrowsLines) and (not FPolyLine.FArrowsLines.IsSolid)
    then
      FIsPolyLineSolid := False;
  end;
end;

procedure TsgCreatorSegments.CrossingSegments(const AIsLinear1,
  AIsLinear2: Boolean; const APts1, APts2: TsgIndexes4);
begin
  if (APts1[0] <> APts2[0]) and (APts1[0] > cnstEmptyPoints) and
    (APts2[0] > cnstEmptyPoints) then
  begin
    if AIsLinear1 then
    begin
      if AIsLinear2 then
        JoinSegments(APts1, APts2)
      else
        ExtendSegments(True, APts1, APts2);
    end
    else
    begin
      if AIsLinear2 then
        ExtendSegments(False, APts2, APts1);
    end;
  end;
end;

destructor TsgCreatorSegments.Destroy;
begin
  FPolyLine := nil;
  FDottedSingPts.Free;
  FreeAndNil(FCounts);
  ClearPFPoints;
  FreeAndNil(FPoints);
  inherited Destroy;
end;

function TsgCreatorSegments.DistanceIndexes(const I1, I2: Integer): Double;
begin
  Result := Sqrt(DistanceIndexesSqr(I1, I2));
end;

function TsgCreatorSegments.DistanceIndexesSqr(const I1, I2: Integer): Extended;
begin
  Result := DistanceFPointSqr(FArrows[I1], FArrows[I1]);
end;

procedure TsgCreatorSegments.ExtendSegments(const AIsFirstLine: Boolean;
  const APtsLine, APtsCircle: TsgIndexes4);
var
  vCross1, vCross2: TFPoint;
  vActPtsLine, vActPtsCircle: TsgIndexes4;
begin
  SetActiveEdges(AIsFirstLine, APtsLine, vActPtsLine);
  SetActiveEdges(not AIsFirstLine, APtsCircle, vActPtsCircle);
  if IsCrossIndexes(vActPtsCircle[0], vActPtsCircle[3], vActPtsLine[0],
    vActPtsLine[1], @vCross1) and IsCrossIndexes(vActPtsCircle[0],
    vActPtsCircle[3], vActPtsLine[3], vActPtsLine[2], @vCross2) then
  begin
    if IsCorrectExtendedAngle(vCross1, FArrows[vActPtsLine[0]],
      FArrows[vActPtsCircle[0]]) and IsCorrectExtendedAngle(vCross2,
      FArrows[vActPtsLine[3]], FArrows[vActPtsCircle[3]]) then
    begin
      SetPFPoint2DValue(vActPtsLine[0], vCross1);
      SetPFPoint2DValue(vActPtsLine[3], vCross2);
    end;
  end;
end;

function TsgCreatorSegments.GetCenterIndexes(const AIndexes
  : TsgIndexes4): TsgLine;
begin
  Result.Point1 := MiddleFPoint(FArrows[AIndexes[0]], FArrows[AIndexes[3]]);
  Result.Point2 := MiddleFPoint(FArrows[AIndexes[1]], FArrows[AIndexes[2]]);
end;

function TsgCreatorSegments.GetPFPoint(const APoints: TFPointList;
  var AIndex: Integer): PFPoint;
begin
  if AIndex >= APoints.Count then
    AIndex := 0;
  Result := @APoints.List[AIndex];
end;

function TsgCreatorSegments.GetPolyPoint(AIndex: Integer): TFPoint;
begin
  if AIndex >= FPolyPoints.Count then
    AIndex := 0;
  Result := FPolyPoints.List[AIndex];
end;

function TsgCreatorSegments.GetSegment(const AP1, AP2, AD1, AD2: TFPoint)
  : TsgPoints4;
begin
  Result[0] := AddFPoint(AP1, AD1);
  Result[1] := AddFPoint(AP2, AD2);
  Result[2] := SubFPoint(AP2, AD2);
  Result[3] := SubFPoint(AP1, AD1);
end;

function TsgCreatorSegments.GetSegmentLinear(const AP1, AP2: TFPoint;
  const AW1, AW2: Double): TsgPoints4;
var
  vDelta1, vDelta2, vSinCos: TFPoint;
begin
  if FSegmentSinCos.X = FSegmentSinCos.Y then // load incorrect points
  begin
    vSinCos := GetFPointSinCosByFPoints(AP1, AP2);
    FPointSinCosRot90(vSinCos);
  end
  else
    vSinCos := FSegmentSinCos;
  vDelta1 := MakeFPoint(AW1 * vSinCos.X, AW1 * vSinCos.Y, 0);
  vDelta2 := MakeFPoint(AW2 * vSinCos.X, AW2 * vSinCos.Y, 0);
  Result := GetSegment(AP1, AP2, vDelta1, vDelta2);
end;

function TsgCreatorSegments.GetSegmentCircular(const APC, AP1, AP2: TFPoint;
  const AW1, AW2: Double): TsgPoints4;
var
  vDelta1, vDelta2: TFPoint;
  vAngle, vSin, vCos: Extended;
begin
  vAngle := GetAngleByPoints(APC, AP1, True);
  SinCos(vAngle, vSin, vCos);
  vDelta1 := MakeFPoint(-AW1 * vCos, -AW1 * vSin, 0);
  vAngle := GetAngleByPoints(APC, AP2, True);
  SinCos(vAngle, vSin, vCos);
  vDelta2 := MakeFPoint(-AW2 * vCos, -AW2 * vSin, 0);
  Result := GetSegment(AP1, AP2, vDelta1, vDelta2);
end;

function TsgCreatorSegments.GetStartAndEndWidths(const AVertex: TsgDXFVertex;
  var AStartWidth, AEndWidth: Double): Boolean;
begin
  Result := not IsNillWidth(AVertex);
  if Result then
  begin
    if FPolyLine.FGlobalW = 0 then
    begin
      AStartWidth := AVertex.StartWidth;
      AEndWidth := AVertex.EndWidth;
    end
    else
    begin
      AStartWidth := FPolyLine.FGlobalW;
      AEndWidth := FPolyLine.FGlobalW;
    end;
  end;
end;

function TsgCreatorSegments.GetVertex(const AIndex: Integer): TsgDXFVertex;
var
  vVertexFirst: Integer;
begin
  if AIndex >= VertexesCount then
  begin
    vVertexFirst := VertexFirst;
    if vVertexFirst >= FPolyLine.FEntities.Count then
      vVertexFirst := 0;
    Result := FPolyLine.FEntities.List[vVertexFirst];
  end
  else
    Result := FPolyLine.FEntities.List[AIndex];
end;

function TsgCreatorSegments.GetVertexesCount: Integer;
begin
  if FVertexCount < 0 then
  begin
    FVertexCount := FPolyLine.FEntities.Count;
    while (FVertexCount > 0) and (FPolyCounts[FVertexCount - 1] = -1) do
      Dec(FVertexCount);
  end;
  Result := FVertexCount;
end;

function TsgCreatorSegments.GetVertexFirst: Integer;
begin
  if FVertexFirst < 0 then
  begin
    FVertexFirst := 0;
    while (FVertexFirst < VertexesCount) and
      (FPolyCounts[FVertexCount - 1] = -1) do
      Inc(FVertexFirst);
  end;
  Result := FVertexFirst;
end;

function TsgCreatorSegments.IsCorrectExtendedAngle(const APB, AP1,
  AP2: TFPoint): Boolean;
const
  cnstExtendedMinAngle = 14.5;
var
  vAngle: Double;
begin
  Result := False;
  vAngle := GetAngleOfLinesEx(APB, AP1, AP2);
  if (vAngle >= cnstExtendedMinAngle) then
    Result := True;
end;

function TsgCreatorSegments.IsCorrectJoinAngle(const APB, AP1,
  AP2: TFPoint): Boolean;
const
  cnstJoinMinAngle = 29;
  cnstJoinMaxAngle = 170;
var
  vAngle: Double;
begin
  Result := False;
  vAngle := GetAngleOfLinesEx(APB, AP1, AP2);
  if (vAngle > cnstJoinMinAngle) then
    Result := True;
end;

function TsgCreatorSegments.IsCrossIndexes(const I11, I12, I21, I22: Integer;
  const ACross: PFPoint): Boolean;
begin
  Result := IsCrossLinesPts(FArrows[I11], FArrows[I12], FArrows[I21],
    FArrows[I22], ACross, fExtendedResolution);
end;

function TsgCreatorSegments.IsNillWidth(const AVertex: TsgDXFVertex): Boolean;
begin
  Result := (FPolyLine.FGlobalW = 0) and (AVertex.StartWidth = 0) and
    (AVertex.EndWidth = 0);
end;

procedure TsgCreatorSegments.JoinSegments(const APts1, APts2: TsgIndexes4);
var
  vCross1, vCross2: TFPoint;
  vLine1, vLine2: TsgLine;
  vWidth1, vWidth2: Extended;
begin
  vLine1 := GetCenterIndexes(APts1);
  vLine2 := GetCenterIndexes(APts2);
  if IsParalleniarLines(vLine1, vLine2) then
  begin
    vWidth1 := DistanceIndexesSqr(APts1[1], APts1[2]);
    vWidth2 := DistanceIndexes(APts2[0], APts2[3]);
    if vWidth1 <= vWidth2 then // variant: ->
      Exit;
  end;
  if IsCrossIndexes(APts1[0], APts1[1], APts2[0], APts2[1], @vCross1) and
    IsCrossIndexes(APts1[3], APts1[2], APts2[3], APts2[2], @vCross2) then
  begin
    if IsCorrectJoinAngle(vCross1, FArrows[APts1[0]], FArrows[APts2[1]]) and
      IsCorrectJoinAngle(vCross2, FArrows[APts1[3]], FArrows[APts2[2]]) then
    begin
      if not(IsEqualFPoints(FArrows[APts1[0]], vCross1) or
        IsEqualFPoints(FArrows[APts1[3]], vCross2)) then
      begin
        SetPFPoint2DValue(APts1[1], vCross1);
        SetPFPoint2DValue(APts1[2], vCross2);

        SetPFPoint2DValue(APts2[0], vCross1);
        SetPFPoint2DValue(APts2[3], vCross2);
      end;
    end;
  end;
end;

procedure TsgCreatorSegments.LoadSegments(const AsSolid: Boolean = False);
var
  I, vLastIndexVertex: Integer;
  vStartWidth, vEndWidth, vRadius: Double;
  vBulgeCenter: TFPoint;
  vCenter, vPoint: PFPoint;
  V0, V1: TsgDXFVertex;
begin
  if (FPolyLine = nil) or (FPolyPoints = nil) or (FPolyCounts = nil) or
    (FPolyLine.Count < 1) then
    Exit;
  FIsManyDottedPoints := AsSolid;
  FVertexCount := -1;
  FVertexFirst := -1;
  CheckGlobalWidth;
  FPointsIndex := 0;
  FSegmentFirst := cnstIndexesNoInit;
  FSegmentLast := cnstIndexesNoInit;
  vLastIndexVertex := VertexesCount - 2 + Integer(FIsPolylineClosed);
  if FPolyLine.FArrows = nil then
    FPolyLine.FArrows := TFPointList.Create;
  if UseAsSolid then
    FPolyLine.FArrowsLines := nil;
  FArrows := FPolyLine.FArrows;
  FArrows.Clear;
  try
    for I := VertexFirst to vLastIndexVertex do
    begin
      FPointsCount := FPolyCounts[I];
{$IFDEF EVG}
      if FPointsCount = -1 then
        Continue;
{$ENDIF}
      V0 := Vertexes[I];
      if GetStartAndEndWidths(V0, vStartWidth, vEndWidth) then
      begin
        FStartWidth := 0.5 * vStartWidth;
        FEndWidth := 0.5 * vEndWidth;
        vCenter := nil;
        if FPointsCount > 1 then
        begin
          V1 := Vertexes[I + 1];
          vBulgeCenter := GetCenterOfBulge(V0.Point, V1.Point, V0.Bulge);
          vRadius := DistanceFPoint(vBulgeCenter, PolyPoints[FPointsIndex]);
          if vRadius > fDoubleResolution then
          begin
            if FStartWidth > vRadius then
              FStartWidth := vRadius;
            if FEndWidth > vRadius then
              FEndWidth := vRadius;
          end;
          vCenter := @vBulgeCenter;
        end;
        LoadPoinstBySegment(FIsPolylineClosed and
          (I = vLastIndexVertex), vCenter);
      end
      else
      begin
        FSegmentLast[0] := cnstNoInitPoints;
        Inc(FPointsIndex, FPointsCount);
      end;
    end;
    if (FPolyLine.FArrows <> nil) and (FPolyExtrusion <> nil) then
    begin
      for I := 0 to FPolyLine.FArrows.Count - 1 do
      begin
        vPoint := @FPolyLine.FArrows.List[I];
        DoExtrusion(vPoint^, FPolyExtrusion^);
      end;
    end;
  except
    if FPolyLine.FArrows <> nil then
      FPolyLine.FArrows.Clear(True);
    raise;
  end;
end;

// 0,3 - active points
procedure TsgCreatorSegments.SetActiveEdges(const AIsFirst: Boolean;
  const APts: TsgIndexes4; var AActPts: TsgIndexes4);
begin
  if AIsFirst then
  begin
    AActPts[0] := APts[1];
    AActPts[1] := APts[0];
    AActPts[3] := APts[2];
    AActPts[2] := APts[3];
  end
  else
    AActPts := APts;
end;

procedure TsgCreatorSegments.SetPFPoint2DValue(const AIndex: Integer;
  const AValue: TFPoint);
var
  vPoint: PFPoint;
begin
  vPoint := @FArrows.List[AIndex];
  vPoint^.X := AValue.X;
  vPoint^.Y := AValue.Y;
end;

function TsgCreatorSegments.UseAsSolid: Boolean;
begin
  Result := FIsPolyLineSolid or FIsManyDottedPoints;
end;

{ TsgDXFField }

procedure TsgDXFField.AssignEntity(Source: TsgDXFEntity);
var
  I: Integer;
  vField, vNewChildField: TsgDXFField;
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFField then
  begin
    vField := TsgDXFField(Source);
    FCache.AssignData(vField.Cache);
    FDataSet.AssignData(vField.DataSet);
    FChildFields.Clear;
    for I := 0 to vField.Count - 1 do
    begin
      vNewChildField := TsgDXFField.Create;
      vNewChildField.AssignEntity(vField.ChildFields[I]);
      FChildFields.Add(vNewChildField);
      if Assigned(vField.Owner) then
        vField.Owner.AddEntity(vNewChildField);
    end;
    FEvaluatorID := vField.EvaluatorID;
    FExpression := vField.Expression;
    FFieldCode := vField.FieldCode;
    FFormat2Digits := vField.Format2Digits;
    FObjectIDs.Assign(vField.ObjectIDs);
    FOverflowFieldCode := vField.OverflowFieldCode;
  end;
end;

type
  TsgCADExtendedDataAccess = class(TsgCADExtendedData);

procedure TsgDXFField.ClearReferences;
begin
  inherited ClearReferences;
  FChildFields.Clear;
  TsgCADExtendedDataAccess(FCache).ClearData;
  TsgCADExtendedDataAccess(FDataSet).ClearData;
  FObjectIDs.Clear;
end;

constructor TsgDXFField.Create;
begin
  inherited Create;
  FChildFields := TList.Create;
  FCache := TsgCADExtendedData.Create;
  FDataSet := TsgCADExtendedData.Create;
  FObjectIDs := TsgInt64List.Create;
end;

function TsgDXFField.EntName: string;
begin
  Result := inherited EntName + ' ' + FFieldCode;
end;

procedure TsgDXFField.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FChildFields);
  FreeAndNil(FCache);
  FreeAndNil(FDataSet);
  FreeAndNil(FObjectIDs);
end;

procedure TsgDXFField.GenerateFieldCode;
begin
  FFieldCode := '';
  if Pos('Ac', FEvaluatorID) = 1 then
    FFieldCode := '\' + FEvaluatorID;
  if FFieldCode <> '' then
    FFieldCode := FFieldCode + ' ';
  if FEvaluatorID = cnstAcExpr then
    FFieldCode := FFieldCode + '(' + FExpression + ')'
  else
    FFieldCode := FFieldCode + FExpression;
  if FFormat2Digits then
    FFieldCode := FFieldCode + ' ' + cnstFormat2Digits;
  if FOverflowFieldCode <> '' then
    FFieldCode := FFieldCode + ' "' + FOverflowFieldCode + '"';
end;

procedure TsgDXFField.LoadedInternal(AConverter: TsgDXFConverter);
var
  vPos: Integer;
begin
  inherited LoadedInternal(AConverter);
  if FFieldCode <> '' then
  begin
    FExpression := Trim(FFieldCode);
    vPos := Pos('"' + FOverflowFieldCode + '"', FExpression);
    if vPos > 0 then
    begin
      Delete(FExpression, vPos, MaxInt);
      FExpression := TrimRight(FExpression);
    end;
    vPos := Pos(cnstFormat2Digits, FExpression);
    if vPos = Length(FExpression) - 1 then
    begin
      Delete(FExpression, vPos, MaxInt);
      FExpression := TrimRight(FExpression);
      FFormat2Digits := True;
    end;
    vPos := Pos(FEvaluatorID, FFieldCode);
    if vPos > 0 then
      FExpression :=
        TrimLeft(Copy(FExpression, vPos + Length(FEvaluatorID), MaxInt));
    FExpression := ClearBrackets(FExpression);
  end
  else
    GenerateFieldCode;
end;

{ TsgDXFOwneredItem }

procedure TsgDXFOwneredItem.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFOwneredItem then
  begin
    Name := TsgDXFOwneredItem(Source).Name;
  end;
end;

procedure TsgDXFOwneredItem.ClearReferences;
begin
  inherited ClearReferences;
  SetOwner(nil);
end;

constructor TsgDXFOwneredItem.Create;
begin
  inherited Create;
  FNamedItem := TsgNamedItem.Create(Self);
end;

function TsgDXFOwneredItem.EntName: string;
begin
  Result := FNamedItem.Name;
  if Result = '' then
    Result := inherited EntName;
end;

procedure TsgDXFOwneredItem.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FNamedItem);
end;

function TsgDXFOwneredItem.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlName:
      Name := ANode.ValueAsStr;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFOwneredItem.GetConverter: TsgDXFConverter;
begin
  Result := inherited GetConverter;
end;

function TsgDXFOwneredItem.GetHandle: UInt64;
begin
  Result := FHandle;
end;

function TsgDXFOwneredItem.GetName: string;
begin
  Result := FNamedItem.Name;
end;

function TsgDXFOwneredItem.GetNamedItem: TObject;
begin
  Result := FNamedItem;
end;

function TsgDXFOwneredItem.GetOwner: TsgDXFEntity;
begin
  Result := FNamedItem.Owner;
end;

function TsgDXFOwneredItem.GetStrValue: string;
begin
  Result := FNamedItem.Name;
end;

procedure TsgDXFOwneredItem.SetHandle(const Value: UInt64);
begin
  FHandle := Value;
end;

procedure TsgDXFOwneredItem.SetName(const AName: string);
begin
  FNamedItem.Name := AName;
end;

procedure TsgDXFOwneredItem.SetOwner(const AValue: TsgDXFEntity);
begin
  FNamedItem.Owner := AValue;
end;

function TsgDXFOwneredItem.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlName].Name).Value := Name;
end;

{ TsgDXFFieldList }

procedure TsgDXFFieldList.ListNotify(Ptr: Pointer; Action: TListNotification);
var
  I: Integer;
begin
  inherited ListNotify(Ptr, Action);
  if Action in [lnExtracted, lnDeleted] then
    for I := Count - 1 downto 0 do
      if Entities[I] is TsgDXFField then
        TsgDXFField(Entities[I]).ChildFields.Remove(Ptr);
end;

{ TsgAcadTableGenerator }

function TsgAcadTableGenerator.AddLineData(const AHorz: Boolean;
  const ACell: TsgAcadTableCell; const ABorder, ASpan: Integer)
  : PCellBorderLineData;
begin
  New(Result);
  Result^.ID := 0;
  Result^.Cell := ACell;
  Result^.Border := ABorder;
  Result^.Span := ASpan;
  TList(FData[FIndex[AHorz] - FRange.Start[AHorz]])
    [FIndex[not AHorz] - FRange.Start[not AHorz]] := Result;
end;

constructor TsgAcadTableGenerator.Create(const AConv: TsgDXFConverter;
  const AAcadTable: TsgDXFAcadTable);
begin
  FAcadTable := AAcadTable;
  FConv := AConv;
  FRange.R := Classes.Rect(0, 0, FAcadTable.NumCols - 1,
    FAcadTable.NumRows - 1);
  FData := TList.Create;
end;

constructor TsgAcadTableGenerator.CreateRanged(const AConv: TsgDXFConverter;
  const AAcadTable: TsgDXFAcadTable; const ARange: TRect);
begin
  Create(AConv, AAcadTable);
  FRange.R := ARange;
end;

destructor TsgAcadTableGenerator.Destroy;
begin
  FreeRecordListOfList(FData);
  inherited Destroy;
end;

function TsgAcadTableGenerator.GenerateBlock: TsgDXFBlock;
const
  cnstFldIdx = '_FldIdx';

var
  vCell: TsgAcadTableCell;
  I, J, C, R: Integer;
  vSolids: TList;
  vMTextes: TList;
  vLines: TList;
  vField: TsgDXFField;

  procedure LoadsAndAdd(const AList: TList);
{$IFDEF SGDEL_XE2}
  var
    K, C: Integer;
  begin
    C := AList.Count - 1;
    for K := 0 to C do
    begin
      FConv.DoCreate(AList.List[K]);
      FConv.Loads(AList.List[K]);
      Result.AddEntity(AList.List[K]);
    end;
  end;
{$ELSE}

  var
    K, C: Integer;
    vPList: PPointerList;
  begin
    vPList := @AList.List[0];
    C := AList.Count - 1;
    for K := 0 to C do
    begin
      FConv.DoCreate(vPList^[K]);
      FConv.Loads(vPList^[K]);
      Result.AddEntity(vPList^[K]);
    end;
  end;
{$ENDIF}
function CreateSolid(const ACell: TsgAcadTableCell; const ARect: TFRect)
  : TsgDXFSolid;
begin
  Result := TsgDXFSolid.Create;
  Result.ColorCAD := ACell.FillColor;
  Result.Point := ARect.TopLeft;
  Result.Point1 := MakeFPoint(ARect.Right, ARect.Top, 0);
  Result.Point2 := MakeFPoint(ARect.Left, ARect.Bottom, 0);
  Result.Point3 := ARect.BottomRight;
end;

begin
if FAcadTable.IsBlockInternal then
begin
  if Assigned(FAcadTable.Block) then
  begin
    FAcadTable.Block.Clear(True);
    Result := FAcadTable.Block;
    FAcadTable.Block := nil;
  end
  else
    Result := FAcadTable.CreateBlock(FConv);

  // generate table objects
  vSolids := TList.Create;
  vMTextes := TList.Create;
  vLines := TList.Create;
  try
    // for each cell
    R := 0;
    while R < FAcadTable.NumRows do
    begin
      C := 0;
      while C < FAcadTable.NumCols do
      begin
        vCell := FAcadTable.Cell[C, R];
        if vCell.IsBaseCell then
        begin
          Inc(C, vCell.MergedWidth - 1);
          // create solid entities
          if vCell.BkColorOn then
            vSolids.Add(CreateSolid(vCell, vCell.GetMergedRect));
          // create MText entities
          vField := vCell.Field;
          if Assigned(vField) then
          begin
            I := Pos(cnstFldIdx, vField.FieldCode);
            if I > 0 then
            begin
              Val(Copy(vField.FieldCode, I + Length(cnstFldIdx) + 1,
                MaxInt), I, J);
              vField := TsgDXFField(vField.ChildFields[I]);
              if vField.Cache.HasCode(301, @I) then
                vCell.Text := vField.Cache.DataString[I];
              vMTextes.Add(CreateMText(vCell, False, False));
            end;
          end
          else if vCell.IsTextType and (vCell.Text <> '') then
            vMTextes.Add(CreateMText(vCell, False, False));
        end;
        Inc(C);
      end;
      Inc(R);
    end;

    GenerateLines(vLines, True);
    GenerateLines(vLines, False);

    LoadsAndAdd(vSolids);
    LoadsAndAdd(vMTextes);
    LoadsAndAdd(vLines);
    FConv.Loads(Result);
  finally
    vSolids.Free;
    vMTextes.Free;
    vLines.Free;
  end;
end;
end;

procedure TsgAcadTableGenerator.GenerateLines(const ALines: TList;
  const AHoresontal: Boolean);
const
  cnstDefPointsID = -1;

type
  TFRectEx = packed record
    case Integer of
      0:
        (R: TFRect);
      1:
        (Start: array [Boolean] of TsgFloat; Z1: TsgFloat;
          Finish: array [Boolean] of TsgFloat; Z2: TsgFloat);
  end;

var
  J, vSpan, vID: Integer;
  H, vHorz, vNotH: Boolean;
  vCells: array [Boolean] of TsgAcadTableCell;
  vBorder: array [Boolean] of Integer;
  vIsTopCell: Boolean;
  vLineData, vLineData1: PCellBorderLineData;
  vR: TFRectEx;

  function CreateLine(const AColor: TsgColorCAD; const ALineWeight: Double;
    const AVisibility: Boolean; const APoint, APoint1: TFPoint)
    : TsgDXFLine; overload;
  begin
    Result := TsgDXFLine.Create;
    Result.ColorCAD := AColor;
    Result.LineWeight := ALineWeight;
    Result.Point := APoint;
    Result.Point1 := APoint1;
    // Result.Visibility := AVisibility;
  end;

  function CreateLine(ALineData: PCellBorderLineData;
    const APoint, APoint1: TFPoint): TsgDXFLine; overload;
  begin
    Result := CreateLine(ALineData^.Cell.BorderColor[ALineData^.Border],
      ALineData^.Cell.BorderLineWeight[ALineData^.Border], ALineData^.Span <= 0,
      APoint, APoint1);
    if ALineData^.ID = cnstDefPointsID then
    begin
      Result.Layer := FConv.LayerByName(sLayerDefPoints);
      Result.ColorCAD := MakeColorCAD(acIndexColor, clDXFGray);
    end;
  end;

  function IsBorderEq(AData1, AData2: PCellBorderLineData): Boolean;
  begin
    Result := AData1^.Cell.IsBorderEqEx(AData1^.Border, AData2^.Cell,
      AData2^.Border);
  end;

  function IsLineVisibility(AData: PCellBorderLineData): Boolean;
  begin
    Result := AData^.Cell.BorderVisible[AData^.Border] and (AData^.Span <= 0);
  end;

begin
  // if AHoresontal = true, then generate top and bottom border for each row
  // if AHoresontal = false, then generate left and right border for each col
  H := AHoresontal;
  vNotH := not H;
  vHorz := H or vNotH;
  FSgn[H] := 1;
  FSgn[vNotH] := -1;
  if H then
  begin
    vBorder[False] := 5; // top border line style
    vBorder[True] := 2; // bottom border line style
  end
  else
  begin
    vBorder[False] := 4; // left border line style
    vBorder[True] := 1; // right border line style
  end;
  // generate top/left and bottom/right border for each row
  ClearRecordListOfList(FData, False);
  for J := FRange.Start[H] to FRange.Finish[H] + 1 do
    TList(FData[FData.Add(TList.Create)]).Count := FRange.Finish[vNotH] -
      FRange.Start[vNotH] + 1;

  FIndex[vNotH] := FRange.Start[vNotH];
  while FIndex[vNotH] < FRange.Finish[vNotH] + 1 do
  begin
    FIndex[H] := FRange.Start[H];
    AddLineData(H, Cell[H, 0], vBorder[False], 0);
    Inc(FIndex[H]);
    while FIndex[H] < FRange.Finish[H] + 1 do
    begin
      vIsTopCell := True;
      vCells[vIsTopCell] := Cell[H, 0]; // top or left cell
      vCells[not vIsTopCell] := Cell[H, 1]; // bottom or right cell
      if H then
        vSpan := vCells[not vIsTopCell].SpanY
      else
        vSpan := vCells[not vIsTopCell].SpanX;
      if not vCells[vIsTopCell].BorderVisible[vBorder[not vIsTopCell]] and
        vCells[not vIsTopCell].BorderVisible[vBorder[vIsTopCell]] then
        vIsTopCell := False;
      AddLineData(H, vCells[vIsTopCell], vBorder[not vIsTopCell], vSpan);
      Inc(FIndex[H]);
    end;
    AddLineData(H, Cell[H, 1], vBorder[True], 0);
    Inc(FIndex[vNotH]);
  end;
  vID := 1;
  FIndex[H] := FRange.Start[H];
  if FRange.Finish[H] - FRange.Start[H] >= 0 then
    while FIndex[H] <= FRange.Finish[H] + 1 do
    begin
      FIndex[vNotH] := FRange.Start[vNotH];
      vLineData := ActiveCellBorderLineData[H];
      if IsLineVisibility(vLineData) then
        vLineData^.ID := vID
      else if vLineData^.Span > 0 then
        vLineData^.ID := 0
      else
        vLineData^.ID := cnstDefPointsID;
      Inc(FIndex[vNotH]);
      while FIndex[vNotH] < FRange.Finish[vNotH] + 1 do
      begin
        vLineData1 := ActiveCellBorderLineData[H];
        if IsLineVisibility(vLineData) and IsLineVisibility(vLineData1) then
          if IsBorderEq(vLineData, vLineData1) then
            vLineData1^.ID := vLineData^.ID
          else
          begin
            vID := vLineData^.ID;
            Inc(vID);
            vLineData1^.ID := vID;
          end
        else if IsLineVisibility(vLineData1) then
        begin
          Inc(vID);
          vLineData1^.ID := vID;
          vLineData := vLineData1;
        end
        else
        begin
          if vLineData1^.Span <= 0 then
          begin
            vLineData1^.ID := cnstDefPointsID;
            vLineData := vLineData1;
          end
        end;
        Inc(FIndex[vNotH]);
      end;
      Inc(vID);
      Inc(FIndex[H]);
    end;

  vR := TFRectEx(MakeFRect2D(0, 0, 0, 0));
  FIndex[H] := FRange.Start[H];
  if FRange.Finish[H] - FRange.Start[H] >= 0 then
    while FIndex[H] <= FRange.Finish[H] + 1 do
    begin
      FIndex[vNotH] := FRange.Start[vNotH];
      vR.Start[H] := vR.Finish[H];
      vR.Start[vNotH] := 0;
      vR.Finish[vNotH] := 0;
      repeat
        if ActiveCellBorderLineData[H]^.ID = 0 then
        begin
          vR.Finish[vNotH] := vR.Finish[vNotH] + FSgn[H] * Sizes[vNotH];
          vR.Start[vNotH] := vR.Finish[vNotH];
          Inc(FIndex[vNotH]);
        end
        else
        begin
          vLineData := ActiveCellBorderLineData[H];
          while (FIndex[vNotH] < FRange.Finish[vNotH] + 1) and
            (ActiveCellBorderLineData[H]^.ID = vLineData^.ID) and
            (ActiveCellBorderLineData[H]^.ID <> 0) do
          begin
            vR.Finish[vNotH] := vR.Finish[vNotH] + FSgn[H] * Sizes[vNotH];
            Inc(FIndex[vNotH]);
          end;
          ALines.Add(CreateLine(vLineData,
            MakeFPoint(FSgn[vHorz] * vR.Start[not vHorz],
            FSgn[vHorz] * vR.Start[vHorz], 0),
            MakeFPoint(FSgn[vHorz] * vR.Finish[not vHorz],
            FSgn[vHorz] * vR.Finish[vHorz], 0)));
          if FIndex[vNotH] < FRange.Finish[vNotH] + 1 then
            vR.Start[vNotH] := vR.Finish[vNotH];
        end;
      until FIndex[vNotH] >= FRange.Finish[vNotH] + 1;
      if FIndex[H] < FRange.Finish[H] + 1 then
        vR.Finish[H] := vR.Finish[H] + FSgn[vNotH] * Sizes[H];
      Inc(FIndex[H]);
    end;
end;

function TsgAcadTableGenerator.GetActiveCellBorderLineData(AHorz: Boolean)
  : PCellBorderLineData;
begin
  Result := TList(FData[FIndex[AHorz] - FRange.Start[AHorz]])
    [FIndex[not AHorz] - FRange.Start[not AHorz]];
end;

function TsgAcadTableGenerator.GetCell(AHorz: Boolean; ADec: Integer)
  : TsgAcadTableCell;
begin
  if AHorz then
    Result := FAcadTable.Cell[FIndex[not AHorz], FIndex[AHorz] - ADec]
  else
    Result := FAcadTable.Cell[FIndex[AHorz] - ADec, FIndex[not AHorz]];
end;

function TsgAcadTableGenerator.GetSizes(AHorz: Boolean): Double;
begin
  Result := FAcadTable.Sizes[AHorz, FIndex[AHorz]];
end;

function TsgAcadTableGenerator.CreateMText(const ACell: TsgAcadTableCell;
  const ADoCreate, ALoad: Boolean): TsgDXFMText;
var
  vRect: TFRect;
  vPoint: TFPoint;
begin
  Result := TsgDXFMText.Create;
  Result.Hyphenation := True;
  Result.Height := ACell.TextHeight;
  Result.Text := ACell.Text;
  Result.Align := ACell.CellAlignment;
  Result.Style := ACell.TextStyle;
  Result.ColorCAD := ACell.TextColor;
  Result.Angle := ACell.Rotation;
  vRect := ACell.GetMergedRect;
  InflateFRect(@vRect, -FAcadTable.Properties.HorzCellMargin,
    -FAcadTable.Properties.VertCellMargin, 0);
  // Result.RectHeight := vRect.Top - vRect.Bottom;
  Result.RectWidth := vRect.Right - vRect.Left;
  vPoint := AlignByBox(ACell.CellAlignment, vRect, ACell.TextHeight);
  Result.Point := vPoint;
  FConv.Loads(Result);
  vPoint := AlignByBox(ACell.CellAlignment, Result.Box, ACell.TextHeight);
  Result.Point := AddFPoint(Result.Point, SubFPoint(Result.Point, vPoint));
  if ADoCreate then
    FConv.DoCreate(Result);
  if ALoad then
    FConv.Loads(Result);
end;

{ TsgCADWipeoutVariables }

constructor TsgCADWipeoutVariables.Create;
begin
  inherited Create;
  FDisplayImageFrame := cnstWipeoutVariablesDisplayImageFrame;
  Name := cntClassDXFWIPEOUTVARIABLES;
end;

{ TsgCADRasterVariables }

constructor TsgCADRasterVariables.Create;
begin
  inherited Create;
  FDisplayImageFrame := cnstRasterVariablesDisplayImageFrame;
  Name := sRasterVariables;
end;

{$IFDEF DATA_LINK}
{ TsgCADDataLink }

constructor TsgCADDataLink.Create;
begin
  inherited Create;
  FFileName := '';
end;
{$ENDIF}

function GetClassXDataProcs: TsgClassXDataProcs;
begin
{$IFDEF SG_BTI}
  Result := XDataProc__;
{$ELSE}
  Result := nil;
{$ENDIF}
end;

procedure SetClassXDataProcs(const AXDataProcs: TsgClassXDataProcs);
begin
{$IFDEF SG_BTI}
  XDataProc__ := AXDataProcs;
{$ENDIF}
end;

{ TsgDXFSeqend }

function TsgDXFSeqend.GetEntType: TsgCADEntities;
begin
  Result := ceSeqEnd;
end;

{ TsgDXFBlockRecord }

function TsgDXFBlockRecord.AddEntity(const AEntity: TsgDXFEntity): Integer;
begin
  Result := FBlock.AddEntity(AEntity);
end;

procedure TsgDXFBlockRecord.ClearReferences;
begin
  inherited ClearReferences;
  Block := nil;
end;

constructor TsgDXFBlockRecord.Create;
begin
  if FBlock = nil then
  begin
    FBlock := TsgDXFBlock(TsgDXFBlock.NewInstance);
    FBlock.FBlockRecord := Self;
    FBlock.Create;
  end;
  inherited Create;
  // raise Exception.Create('Cannot create ' + ClassName + ' directly');
end;

function TsgDXFBlockRecord.DeleteEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := FBlock.DeleteEntity(AIndex);
end;

function TsgDXFBlockRecord.EntName: string;
begin
  Result := Name;
  if Result = '' then
    Result := inherited EntName;
end;

procedure TsgDXFBlockRecord.ExchangeEntity(AIndex1, AIndex2: Integer);
begin
  FBlock.ExchangeEntity(AIndex1, AIndex2);
end;

procedure TsgDXFBlockRecord.FreeReferences;
begin
  inherited FreeReferences;
  Block.Free;
end;

function TsgDXFBlockRecord.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlName:
      Name := ANode.ValueAsStr;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFBlockRecord.GetName: string;
begin
  Result := FBlock.Name;
end;

function TsgDXFBlockRecord.IndexOfEntity(const AEntity: TsgDXFEntity): Integer;
begin
  Result := FBlock.IndexOfEntity(AEntity);
end;

function TsgDXFBlockRecord.IndexOfName(const AName: string): Integer;
begin
  Result := FBlock.IndexOfName(AName);
end;

function TsgDXFBlockRecord.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  Result := FBlock.InsertEntity(AIndex, AEntity);
end;

procedure TsgDXFBlockRecord.SetName(const AName: string);
begin
  FBlock.Name := AName;
end;

function TsgDXFBlockRecord.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlName].Name).ValueAsStr := Name;
end;

{ TsgDXFPlotSettings }

procedure TsgDXFPlotSettings.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFPlotSettings then
  begin
    FData := TsgDXFPlotSettings(Source).FData;
  end;
end;

constructor TsgDXFPlotSettings.Create;
begin
  inherited Create;
  FData := cnstDefaultPlotSettingsData;
end;

function TsgDXFPlotSettings.GetCadMargins: TF2DRect;
var
  vMargins: TF2DRect;
begin
  vMargins := UnprintableMargin;
  case PlotRotation of
    pr90DegreesCounterCW:
      Result := MakeF2DRect(vMargins.Top, vMargins.Right, vMargins.Bottom,
        vMargins.Left);
    prUpsideDown:
      Result := MakeF2DRect(vMargins.Right, vMargins.Bottom, vMargins.Left,
        vMargins.Top);
    pr90DegreesCW:
      Result := MakeF2DRect(vMargins.Bottom, vMargins.Left, vMargins.Top,
        vMargins.Right);
  else
    Result := vMargins;
  end;
  Result.TopLeft := Pt2XScalar(Result.TopLeft, CustomPrintScaleKoef);
  Result.BottomRight := Pt2XScalar(Result.BottomRight, CustomPrintScaleKoef);
end;

function TsgDXFPlotSettings.GetCadOffset: TF2DPoint;
begin
  Result := Pt2XScalar(PlotOrigin, -CustomPrintScaleKoef);
  case PlotRotation of
    pr90DegreesCounterCW, pr90DegreesCW:
      SwapDoubles(Result.X, Result.Y);
  end;
end;

function TsgDXFPlotSettings.GetCustomPrintScale: TsgPlotScale;
begin
  Result.Numerator := NumeratorOfCustomPrintScale;
  Result.Denomenator := DenominatorOfCustomPrintScale;
end;

function TsgDXFPlotSettings.GetCustomPrintScaleKoef: Double;
var
  vNumValue: Double;
begin
  vNumValue := NumeratorOfCustomPrintScale;
  if PlotPaperUnits = ppuInches then
    vNumValue := vNumValue * cnstMMPerInch;
  if vNumValue <> 0 then
    Result := DenominatorOfCustomPrintScale / vNumValue
  else
    Result := 1;
end;

function TsgDXFPlotSettings.GetIsLandscapePaper: Boolean;
begin
  Result := PlotPaperSize.X > PlotPaperSize.Y;
end;

function TsgDXFPlotSettings.GetLandScape: Boolean;
begin
  Result := IsLandscapePaper;
  if PlotRotation in [pr90DegreesCounterCW, pr90DegreesCW] then
    Result := not Result;
end;

function TsgDXFPlotSettings.GetMagrinsArea: TFRect;
var
  vMarginsSize, vStartPoint: TF2DPoint;
  vMargins: TF2DRect;
begin
  vMarginsSize.X := PlotPaperSize.X * CustomPrintScaleKoef;
  vMarginsSize.Y := PlotPaperSize.Y * CustomPrintScaleKoef;
  case PlotRotation of
    pr90DegreesCounterCW, pr90DegreesCW:
      SwapDoubles(vMarginsSize.X, vMarginsSize.Y);
  end;
  vMargins := GetCadMargins;
  vMarginsSize.X := vMarginsSize.X - (vMargins.Left + vMargins.Right);
  vMarginsSize.Y := vMarginsSize.Y - (vMargins.Top + vMargins.Bottom);
  vStartPoint := GetStartPoint;
  Result.TopLeft := MakeFPointFrom2D(vStartPoint);
  Result.BottomRight := AddFPoint2D(Result.TopLeft,
    MakeFPointFrom2D(vMarginsSize));
end;

function TsgDXFPlotSettings.GetName: string;
begin
  Result := inherited GetName;
end;

function TsgDXFPlotSettings.GetPaperArea: TFRect;
var
  vStartPoint: TF2DPoint;
  vPaperSize: TF2DPoint;
  vCadmargins: TF2DRect;
begin
  vPaperSize := Pt2XScalar(PlotPaperSize, CustomPrintScaleKoef);
  case PlotRotation of
    pr90DegreesCounterCW, pr90DegreesCW:
      SwapDoubles(vPaperSize.X, vPaperSize.Y);
  end;
  vCadmargins := GetCadMargins;
  vStartPoint := GetStartPoint;
  vStartPoint.X := vStartPoint.X - GetCadMargins.Left;
  vStartPoint.Y := vStartPoint.Y - GetCadMargins.Bottom;
  Result.TopLeft := MakeFPointFrom2D(vStartPoint);
  Result.BottomRight := AddFPoint(Result.TopLeft, MakeFPointFrom2D(vPaperSize));
end;

function TsgDXFPlotSettings.GetPlotData: PsgPlotSettingsData;
begin
  Result := @FData;
end;

function TsgDXFPlotSettings.GetPlotFrameArea: TFRect;
begin
  Result.Left := PlotWindowAreaMin.X;
  Result.Top := PlotWindowAreaMin.Y;
  Result.Right := PlotWindowAreaMax.X;
  Result.Bottom := PlotWindowAreaMax.Y;
  Result.Z1 := 0;
  Result.Z2 := 0;
end;

function TsgDXFPlotSettings.GetPrintableArea: TFRect;
var
  vFrameArea: TFRect;
  vMarginArea: TFRect;

  procedure FlipRect(var ARect: TFRect);
  begin
    if ARect.Left > ARect.Right then
      SwapDoubles(ARect.Left, ARect.Right);
    if ARect.Bottom > ARect.Top then
      SwapDoubles(ARect.Top, ARect.Bottom);
  end;

begin
  vMarginArea := GetMagrinsArea;
  if (PlotType = ptWindowSpecified) then
  begin
    vFrameArea := GetPlotFrameArea;
    vFrameArea := PlotFrameArea;
    FlipRect(vFrameArea);
    FlipRect(vMarginArea);
    Result.Left := Max(vFrameArea.Left, vMarginArea.Left);
    Result.Top := Min(vFrameArea.Top, vMarginArea.Top);
    Result.Right := Min(vFrameArea.Right, vMarginArea.Right);
    Result.Bottom := Max(vFrameArea.Bottom, vMarginArea.Bottom);
    Result.Z1 := 0;
    Result.Z2 := 0;
  end
  else
    Result := vMarginArea;
end;

function TsgDXFPlotSettings.GetRotatedMargin: TF2DRect;
begin
  case PlotRotation of
    pr90DegreesCounterCW:
      Result := MakeF2DRect(UnprintableMargin.Bottom, UnprintableMargin.Left,
        UnprintableMargin.Top, UnprintableMargin.Right);
    prUpsideDown:
      Result := MakeF2DRect(UnprintableMargin.Right, UnprintableMargin.Bottom,
        UnprintableMargin.Left, UnprintableMargin.Top);
    pr90DegreesCW:
      Result := MakeF2DRect(UnprintableMargin.Top, UnprintableMargin.Right,
        UnprintableMargin.Bottom, UnprintableMargin.Left);
  else
    Result := UnprintableMargin;
  end;
end;

function TsgDXFPlotSettings.GetStartPoint: TF2DPoint;
var
  vPaperOffset: TF2DPoint;
begin
  if PlotPaperUnits = ppuInches then
  begin
    vPaperOffset.X := -PaperImageOrigin.X / cnstMMPerInch;
    vPaperOffset.Y := -PaperImageOrigin.Y / cnstMMPerInch;
  end
  else
  begin
    vPaperOffset.X := -PaperImageOrigin.X;
    vPaperOffset.Y := -PaperImageOrigin.Y;
  end;
  Result := AddF2DPoint(GetCadOffset, vPaperOffset);
end;

procedure TsgDXFPlotSettings.ResetForDefaultValue(ADefaultValue
  : PsgPlotSettingsData = nil);
begin
  if Assigned(ADefaultValue) then
    FData := ADefaultValue^
  else
    FData := sgDefaultPlotSettingsData;
end;

procedure TsgDXFPlotSettings.SetCustomPrintScale(const AValue: TsgPlotScale);
begin
  NumeratorOfCustomPrintScale := AValue.Numerator;
  DenominatorOfCustomPrintScale := AValue.Denomenator;
end;

function TsgDXFPlotSettings.SetDefaultValueByExtents
  (const ABox: TFRect): Boolean;
const
  cnstMM: Boolean = True;
var
  vMargins: TF2DRect;
  vName: string;
  vLandScape: Boolean;
begin
  Result := False;
  vName := '';
  PlotType := ptDrawingExtents;
  PlotLayoutFlags := PlotLayoutFlags + [plfUseStandardScale];
  StandardScaleType := 0;
  PrintOrConfigName := cnstNoneDevice;
  PlotPaperUnits := ppuMM;
  PlotPaperSize := GetPrinterActualPaperSize(ABox, vName, @vMargins);
  PaperSize := vName;
  vLandScape := GetLandScale(PlotPaperSize);
  if vLandScape xor GetLandScale(GetSizeFRect(ABox)) then
    PlotRotation := pr90DegreesCounterCW;
  UnprintableMargin := vMargins;
  PlotOrigin := cnstF2DPointZero;
  if IsBadRect(ABox) then
  begin
    DenominatorOfCustomPrintScale := 1;
    NumeratorOfCustomPrintScale := 1;
  end
  else
  begin
    CustomPrintScale := CalcFitScale(ABox, vMargins, PlotPaperSize,
      PlotRotation = pr90DegreesCounterCW, cnstMM);
    PaperImageOrigin := MakeF2DPoint(-ABox.Left, -ABox.Bottom);
    Result := True;
  end;
end;

procedure TsgDXFPlotSettings.SetLandScape(const AValue: Boolean);
begin
  if IsLandscapePaper then
  begin
    if AValue then
      PlotRotation := prNoRotation
    else
      PlotRotation := pr90DegreesCW;
  end
  else
  begin
    if AValue then
      PlotRotation := pr90DegreesCW
    else
      PlotRotation := prNoRotation;
  end;
end;

procedure TsgDXFPlotSettings.SetName(const AName: string);
begin
  inherited SetName(AName);
  FData.PageSetupName := Name;
end;

{ TsgDXFDictionaryVar }

procedure TsgDXFDictionaryVar.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFDictionaryVar then
  begin
    FValue := TsgDXFDictionaryVar(Source).FValue;
    FIntVal := TsgDXFDictionaryVar(Source).FIntVal;
  end;
end;

constructor TsgDXFDictionaryVar.Create;
begin
  inherited Create;
  Name := cnstDictionaryVar;
end;

function TsgDXFDictionaryVar.EntName: string;
begin
  Result := GetName;
  if Result = '' then
    Result := inherited EntName;
end;

function TsgDXFDictionaryVar.GetValue: string;
begin
  Result := FValue;
end;

procedure TsgDXFDictionaryVar.SetValue(const AValue: string);
begin
  FValue := AValue;
end;

function TsgDXFDictionaryVar.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlDictionaryValue].Name).ValueAsStr := Value;
end;

function TsgDXFDictionaryVar.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlDictionaryValue:
      Value := ANode.ValueAsStr;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

{ TsgDXFDimensionStyleProperties }

procedure TsgDXFDimensionProperties.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  FPropertiesInit := [];
  FOwnerStyleItem.Item := nil;
  if Source is TsgDXFDimensionProperties then
  begin
    FOwnerStyleItem.Item := TsgDXFDimensionProperties(Source)
      .FOwnerStyleItem.Item;
    FPropertiesInit := TsgDXFDimensionProperties(Source).FPropertiesInit;
  end;
end;

procedure TsgDXFDimensionProperties.ClearReferences;
begin
  inherited ClearReferences;
  FOwnerStyleItem.Item := nil;
end;

constructor TsgDXFDimensionProperties.Create;
begin
  inherited Create;
  FOwnerStyleItem := TsgTableItem.Create;
end;

procedure TsgDXFDimensionProperties.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FOwnerStyleItem);
end;

function TsgDXFDimensionProperties.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  if AType.ID = xmlName then
    Result := cnstXML_OK
  else
  begin
    Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
    if Result = cnstXML_OK then
    begin
      case AType.ID of
        // xmlDimAlt:   Include(FPropertiesInit, vnDIMAlt);
        // xmlDimAltF:  Include(FPropertiesInit, vnDIMAltF);
        // xmlDimAPost: Include(FPropertiesInit, vnDIMAPost);
        xmlDimAsz:
          Include(FPropertiesInit, vnDIMASZ);
        xmlDimSah:
          Include(FPropertiesInit, vnDIMSAH);
        xmlDimCen:
          Include(FPropertiesInit, vnDIMCEN);
        xmlDimClrD:
          Include(FPropertiesInit, vnDIMCLRD);
        xmlDimClrE:
          Include(FPropertiesInit, vnDIMCLRE);
        xmlDimClrT:
          Include(FPropertiesInit, vnDIMCLRT);
        xmlDimSD1:
          Include(FPropertiesInit, vnDIMSD1);
        xmlDimSD2:
          Include(FPropertiesInit, vnDIMSD2);
        xmlDimSE1:
          Include(FPropertiesInit, vnDIMSE1);
        xmlDimSE2:
          Include(FPropertiesInit, vnDIMSE2);
        xmlDimDec:
          Include(FPropertiesInit, vnDIMDEC);
        xmlDimExe:
          Include(FPropertiesInit, vnDIMEXE);
        xmlDimExo:
          Include(FPropertiesInit, vnDIMEXO);
        xmlDimGap:
          Include(FPropertiesInit, vnDIMGAP);
        xmlDimLFac:
          Include(FPropertiesInit, vnDIMLFAC);
        xmlDimLwD:
          Include(FPropertiesInit, vnDIMLWD);
        xmlDimLwE:
          Include(FPropertiesInit, vnDIMLWE);
        // xmlDimPost:  Include(FPropertiesInit, vnDIMPost);
        xmlDimScale:
          Include(FPropertiesInit, vnDIMSCALE);
        xmlDimTad:
          Include(FPropertiesInit, vnDIMTAD);
        xmlDimTih:
          Include(FPropertiesInit, vnDIMTIH);
        xmlDimTix:
          Include(FPropertiesInit, vnDIMTIX);
        xmlDimToh:
          Include(FPropertiesInit, vnDIMTOH);
        xmlDimTxt:
          Include(FPropertiesInit, vnDIMTXT);
      end;
    end;
  end;
end;

function TsgDXFDimensionProperties.GetActualStyle(const ANameValue
  : TsgDimNameVal; const ASetValue: Boolean = False): TsgDXFDimensionStyle;
begin
  if ASetValue then
    Include(FPropertiesInit, ANameValue);
  if (OwnerStyle = nil) or (ANameValue in FPropertiesInit) then
  begin
    Result := inherited GetActualStyle(ANameValue)
  end
  else if Assigned(OwnerStyle) and (OwnerStyle.ClassType <> TsgLinkObject) then
    Result := OwnerStyle.GetActualStyle(ANameValue)
  else
    Result := inherited GetActualStyle(ANameValue)
end;

function TsgDXFDimensionProperties.GetConverter: TsgDXFConverter;
begin
  Result := inherited GetConverter;
  if not Assigned(Result) and Assigned(OwnerStyle) and (OwnerStyle <> Self) then
    Result := OwnerStyle.Converter;
end;

{ TsgDXFDimensionStyleProperties }
function TsgDXFDimensionProperties.GetExtData(const AData
  : TsgCADExtendedData): Boolean;

  function GetRefernceHandle(const ABlock: TsgDXFBlock): UInt64;
  begin
    Result := cnstBadHandle;
    if ABlock <> nil then
      Result := ABlock.BlockRecord.Handle;
  end;

  procedure AddFloat(AName: TsgDimNameVal; ACode: Integer; AValue: Double);
  begin
    if AName in FPropertiesInit then
    begin
      AData.AddInt16(Integer_1070, ACode);
      AData.AddDouble(Float_1040, AValue);
    end;
  end;

  procedure AddInt16(AName: TsgDimNameVal; ACode: Integer; AValue: Integer);
  begin
    if AName in FPropertiesInit then
    begin
      AData.AddInt16(Integer_1070, ACode);
      AData.AddInt16(Integer_1070, AValue);
    end;
  end;

  procedure AddInt64(AName: TsgDimNameVal; ACode: Integer; AValue: UInt64);
  begin
    if AName in FPropertiesInit then
    begin
      AData.AddInt16(Integer_1070, ACode);
      AData.AddInt64(String_1005, AValue);
    end;
  end;

begin
  Result := False;
  if Assigned(AData) and (FPropertiesInit <> []) then
    try
      BeginExtData(AData);
      AddFloat(vnDIMSCALE, Float_40, Scale);
      AddFloat(vnDIMASZ, Float_41, ArrowSize);
      AddFloat(vnDIMEXO, Float_42, ExtLineOffset);
      AddFloat(vnDIMEXE, Float_44, ExtLineExt);
      AddInt16(vnDIMTIH, Integer_73, Ord(DIMTIH));
      AddInt16(vnDIMTOH, Integer_74, Ord(DIMTOH));
      AddInt16(vnDIMSE1, Integer_75, Ord(DIMSE1));
      AddInt16(vnDIMSE2, Integer_76, Ord(DIMSE2));
      AddInt16(vnDIMTAD, Integer_77, Ord(TextPosVert));
      AddFloat(vnDIMTXT, Float_140, TextHeight);
      AddFloat(vnDIMCEN, Float_141, SizeCenterMark);
      AddFloat(vnDIMLFAC, Float_144, DimLFac);
      AddFloat(vnDIMGAP, Float_147, TextOffset);
      AddInt16(vnDIMSAH, Integer_173, Ord(DIMSAH));
      AddInt16(vnDIMTIX, Integer_174, DIMTIX);
      AddInt16(vnDIMCLRD, Integer_176,
        ConvertColorCADToIndexColor(DIMCLRD, False));
      AddInt16(vnDIMCLRE, Integer_177,
        ConvertColorCADToIndexColor(DIMCLRE, False));
      AddInt16(vnDIMCLRT, Integer_178,
        ConvertColorCADToIndexColor(DIMCLRT, False));
      AddInt16(vnDIMDEC, Integer_271, DIMDEC);
      AddInt16(vnDIMSD1, Word_281, Ord(DIMSD1));
      AddInt16(vnDIMSD2, Word_282, Ord(DIMSD2));
      AddInt64(vnDIMTXSTY, 340, TextStyle.Handle);
      AddInt64(vnDIMLRBLK, 341, GetRefernceHandle(DIMLDRBLK));
      AddInt64(vnDIMBLK, 342, GetRefernceHandle(DIMBLK));
      AddInt64(vnDIMBLK1, 343, GetRefernceHandle(DimBlk1));
      AddInt64(vnDIMBLK2, 344, GetRefernceHandle(DimBlk2));
      AddInt16(vnDIMLWD, 371, ConvertLineWeightToDXF(DIMLWD));
      AddInt16(vnDIMLWE, 372, ConvertLineWeightToDXF(DIMLWE));
      Result := True;
    finally
      EndExtData(AData);
    end;
end;

function TsgDXFDimensionProperties.GetOwnerStyle: TsgDXFDimensionStyle;
begin
  Result := TsgDXFDimensionStyle(FOwnerStyleItem.Item);
end;

function TsgDXFDimensionProperties.GetPropertiesInit: TsgDimNameVals;
begin
  Result := FPropertiesInit;
end;

procedure TsgDXFDimensionProperties.Link(AConverter: TsgDXFConverter);
var
  I: TsgDimNameVal;
begin
  inherited Link(AConverter);
  if Assigned(OwnerStyle) and (OwnerStyle.ClassType = TsgLinkObject) then
    OwnerStyle := TsgDXFDimensionStyle(TsgLinkObject(OwnerStyle)
      .GetObject(AConverter.Sections[csDimStyles]));
  for I := Low(FBlks) to High(FBlks) do
    if Assigned(FBlks[I]) and (FBlks[I].ClassType = TsgLinkObject) then
      SetBlocksInternal(I, TsgDXFBlock(TsgLinkObject(FBlks[I])
        .GetObject(AConverter.Sections[csBlockRecords])));
end;

procedure TsgDXFDimensionProperties.SetOwnerStyle(const AValue
  : TsgDXFDimensionStyle);
begin
  FPropertiesInit := [];
  FOwnerStyleItem.Item := nil;
  if AValue <> nil then
  begin
    AssignEntity(AValue);
    FOwnerStyleItem.Item := AValue;
  end;
end;

{ TsgDXFBlockRecords }

function TsgDXFBlockRecords.AddEntity(const AEntity: TsgDXFEntity): Integer;
begin
  Result := -1;
  if Assigned(Blocks) then
    Result := Blocks.AddEntity(TsgDXFBlockRecord(AEntity).Block);
end;

procedure TsgDXFBlockRecords.Clear(const ADoFree: Boolean);
begin
  // if Assigned(Blocks) then
  // Blocks.Clear(ADoFree); ??
end;

constructor TsgDXFBlockRecords.Create;
begin
  inherited Create;
  Name := cnstTableBLOCK_RECORD;
end;

function TsgDXFBlockRecords.DeleteEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := nil;
  if Assigned(Blocks) then
  begin
    Result := TsgDXFBlock(Blocks[AIndex]).BlockRecord;
    Blocks.DeleteEntity(AIndex);
  end;
end;

procedure TsgDXFBlockRecords.ExchangeEntity(AIndex1, AIndex2: Integer);
begin
  if Assigned(Blocks) then
    Blocks.ExchangeEntity(AIndex1, AIndex2);
end;

function TsgDXFBlockRecords.FindEntByName(const AName: string): TsgDXFEntity;
begin
  Result := nil;
  if Assigned(Blocks) then
  begin
    Result := Blocks.FindEntByName(AName);
    if Assigned(Result) then
      Result := TsgDXFBlock(Result).BlockRecord;
  end;
end;

function TsgDXFBlockRecords.GetBlocks: TsgDXFGroup;
begin
  if not Assigned(FBlocks) then
    if Assigned(Converter) then
      FBlocks := Converter.Sections[csBlocks];
  Result := FBlocks;
end;

function TsgDXFBlockRecords.GetCount: Integer;
begin
  Result := 0;
  if Assigned(Blocks) then
    Result := Blocks.Count
end;

function TsgDXFBlockRecords.GetEntity(const AIndex: Integer): TsgDXFEntity;
begin
  Result := nil;
  if Assigned(Blocks) then
    Result := TsgDXFBlock(Blocks[AIndex]).BlockRecord;
end;

function TsgDXFBlockRecords.GetName: string;
begin
  Result := cnstTableBLOCK_RECORD;
end;

function TsgDXFBlockRecords.IndexOfEntity(const AEntity: TsgDXFEntity): Integer;
begin
  Result := -1;
  if Assigned(Blocks) then
    Result := Blocks.IndexOfEntity(TsgDXFBlockRecord(AEntity).Block);
end;

function TsgDXFBlockRecords.IndexOfName(const AName: string): Integer;
begin
  Result := -1;
  if Assigned(Blocks) then
    Result := Blocks.IndexOfName(AName);
end;

function TsgDXFBlockRecords.InsertEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity): Boolean;
begin
  Result := False;
  if Assigned(Blocks) then
    Result := Blocks.InsertEntity(AIndex, TsgDXFBlockRecord(AEntity).Block);
end;

procedure TsgDXFBlockRecords.Link(AConverter: TsgDXFConverter);
begin
  inherited Link(AConverter);
  Blocks := AConverter.Sections[csBlocks];
end;

procedure TsgDXFBlockRecords.SetBlocks(const Value: TsgDXFGroup);
begin
  FBlocks := Value;
end;

procedure TsgDXFBlockRecords.SetEntity(const AIndex: Integer;
  const AEntity: TsgDXFEntity);
begin
  if Assigned(Blocks) and Assigned(AEntity) then
    Blocks.SetEntity(AIndex, TsgDXFBlockRecord(AEntity).Block);
end;

{ TsgBrepBlock }

procedure TsgBrepIndexFace.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgBrepIndexFace then
  begin
    IndexFaceMap := TsgBrepIndexFace(Source).IndexFaceMap
  end;
end;

function TsgBrepIndexFace.GetEntType: TsgCADEntities;
begin
  Result := ceBrep;
end;

function TsgBrepIndexFace.GroupExists: Boolean;
begin
  Result := True;
end;

function TsgBrepIndexFace.GroupFill(AConverter: TsgDXFConverter): Boolean;
var
  vParams: PsgParamTriangle;
  vInitData: TsgInitMeshBuilderData;
  v3dType: Integer;
  vBrepEntity: TsgBrepGroup;
begin
  New(vParams);
  try
    if vParams <> nil then
    begin
      v3dType := 4;
      vBrepEntity := Self as TsgBrepGroup;
      case vBrepEntity.EntType of
        ceIges:
          v3dType := 0;
        ceStep:
          v3dType := 1;
        ceBrep:
          v3dType := 2;
      end;
      SetParamsByMeshBuilder(vParams, @vInitData);
      vInitData.IndexFaceMap := IndexFaceMap;
      vInitData.File3DType := v3dType;
      vInitData.File3DName := PAnsiChar(AnsiString(vBrepEntity.FileName));
      GetMeshBrep(vInitData, AConverter.MeshQuality);
    end;
  finally
    Dispose(vParams);
  end;
  Result := GroupInternalEntities(AConverter);
end;

function TsgBrepIndexFace.GroupHasAddedEntities: Boolean;
begin
  Result := True;
end;

{ TsgBrepEntity }

function TsgBrepEntity.GroupInternalEntities(AConverter
  : TsgDXFConverter): Boolean;
var
  I, J: Integer;
  vEntity: TsgDXFEntity;
begin
  for I := 0 to Group.Count - 1 do
    Group.Entities[I].Loaded(AConverter);

  FLastGroupIndex := Group.Count - 1;

  // Internal Entities
  for I := 0 to Count - 1 do
  begin
    vEntity := Entities[I];
    if vEntity.GroupExists then
    begin
      if vEntity.GroupCreate(Converter) then
      begin
        for J := 0 to vEntity.Group.Count - 1 do
          Group.AddEntity(vEntity.Group.Entities[J]);
      end
    end
    else
      Group.AddEntity(vEntity);
  end;
  Result := True;
end;

procedure TsgBrepEntity.Invoke(AConverter: TsgDXFConverter;
  Proc, FinishProc: TsgCADEntityProc);
begin
  if Assigned(Proc) then
    Proc(Self);
  try
    inherited Iterate(AConverter, Proc, FinishProc);
  finally
    if Assigned(FinishProc) then
      FinishProc(Self);
  end;
end;

procedure TsgBrepEntity.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
  if Layer = nil then
    Layer := AConverter.LayerByName('0');
end;

// procedure TsgBrepEntity.LoadedInternal(AConverter: TsgDXFConverter);
// begin
// FBox := cnstBadRect;
// if AConverter <> nil then
// SetConverter(AConverter);
// //if CanLoading(Converter) then
// AddBlock(AConverter);
// inherited LoadedInternal(AConverter);
// end;

procedure TsgBrepEntity.MeshBrepBuilder(const AInitParam: TsgInitParam;
  const AData: TsgInitMeshBuilderData;
  const ADeviationCoefficien: Double = 0.001);
begin
  Self.SetColorCAD(ColorCAD);
end;

procedure TsgBrepEntity.GroupClear;
var
  I: Integer;
  vGroup: TsgDXFGroup;
begin
  if GroupExists then
  begin
    vGroup := Group;
    if vGroup <> nil then
    begin
      I := vGroup.Count - 1;
      while I > FLastGroupIndex do
      begin
        vGroup.DeleteEntity(I);
        Dec(I);
      end;
    end;
    FLastGroupIndex := 0;
  end;
  inherited GroupClear;
end;

procedure TsgBrepEntity.SetColorCAD(const Value: TsgColorCAD);
var
  I: Integer;
begin
  FPen.ColorCAD := Value;
  inherited SetColorCAD(Value);
  for I := 0 to Count - 1 do
    Entities[I].ColorCAD := ColorCAD;
end;

procedure TsgBrepEntity.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgBrepEntity then
  begin
    FPen.AssignEntity(TsgBrepEntity(Source).FPen);
  end;
end;

function TsgBrepEntity.CanDraw: Boolean;
begin
  Result := True;
end;

procedure TsgBrepEntity.ClearReferences;
begin
  inherited ClearReferences;
  if Assigned(FPen) then
    FPen.ClearReferences;
end;

constructor TsgBrepEntity.Create;
begin
  inherited Create;
  FPen := TsgDXFPenLine.Create;
end;

procedure TsgBrepEntity.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FPen);
end;

function TsgBrepEntity.GetColorCAD: TsgColorCAD;
begin
  Result := Pen.ColorCAD;
end;

function TsgBrepEntity.GetExtrusion: TFPoint;
begin
  Result := FPen.GetExtrusion;
end;

function TsgBrepEntity.GetLines: TsgLines;
begin
  Result := FPen.Lines;
end;

function TsgBrepEntity.GetLineType: TsgDXFLineType;
begin
  Result := FPen.LineType;
end;

function TsgBrepEntity.GetLineTypeScale: Double;
begin
  Result := FPen.LineTypeScale;
end;

procedure TsgBrepEntity.SetLineType(const AValue: TsgDXFLineType);
begin
  FPen.LineType := AValue;
end;

procedure TsgBrepEntity.SetLineTypeScale(Value: Double);
begin
  FPen.LineTypeScale := Abs(Value);
end;

procedure TsgBrepEntity.SetParamsByMeshBuilder(AParams: PsgParamTriangle;
  AInitData: PsgInitMeshBuilderData);
begin
  AParams^.ASelf := Group;
  AParams^.MeshPointer := nil;
  AParams^.VertexPointer := nil;
  ZeroMemory(AInitData, SizeOf(TsgInitMeshBuilderData));
  AInitData^.TriangleFunc := @GetTriangle;
  AInitData^.MeshParam := AParams;
  AInitData^.NewFaceGroupFunc := nil;
end;

procedure TsgBrepEntity.GetMeshBrep(const AData: TsgInitMeshBuilderData;
  const ADeviationCoefficien: Double = 0.001);
var
  vInitParam: TsgInitParam;
begin
  if not IsLoadMeshBuilderDll then
    Exit;
  ZeroMemory(@vInitParam, SizeOf(vInitParam));
  vInitParam.Parser := AData.Self;
  vInitParam.Creator := AData.Creator;
  vInitParam.DeviationCoefficien := ADeviationCoefficien;
{$IFDEF SG_BREP_TOPOLOGY}
  vInitParam.CalcTopogy := GlobalCalcTopogy;
{$ELSE}
  vInitParam.CalcTopogy := 0;
{$ENDIF}
  vInitParam.Multithreading := GlobalMultithreading;
  vInitParam.GetWire := AData.DrawWireFunc;
  vInitParam.GetIso := AData.DrawISOFunc;
  vInitParam.GetLine := AData.DrawTestFunc;
  vInitParam.StopFunc := AData.StopFunc;
  MeshBrepBuilder(vInitParam, AData, ADeviationCoefficien);
end;

{ TsgBrepFile }

procedure TsgBrepGroup.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgBrepGroup then
  begin
    FName := TsgBrepGroup(Source).FName;
    if ClassType = Source.ClassType then
    begin
      Clear(True);
      AddEntities(Source);
    end;
  end;
end;

constructor TsgBrepGroup.Create;
begin
  inherited Create;
  ZeroMemory(@FContext, SizeOf(FContext));
end;

destructor TsgBrepGroup.Destroy;
begin
  inherited Destroy;
  { TODO: destructor TsgBrepGroup.Destroy; }
  if FContext.Context <> nil then
    sgFreeContext(@FContext);
end;

function TsgBrepGroup.GetContext: PsgContext;
begin
  Result := @FContext;
end;

function TsgBrepGroup.GroupExists: Boolean;
begin
  Result := True;
end;

procedure TsgBrepGroup.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
end;

// const AFile3DType: Integer;
// const AFile3DName: PAnsiChar; const ADrawWireFunc, ADrawISOFunc,
// ADrawTestFunc: TsgCallBackLine; const ATriangleFunc: TsgGetTriangleFunc;
// const ASelf, AMeshParam: Pointer; const ANewFaceGroupFunc: TsgNewFaceGroupFunc;
// const AStopFunc: TsgCallBackStop; const ADeviationCoefficien: Double = 0.001

procedure TsgBrepGroup.MeshBrepBuilder(const AInitParam: TsgInitParam;
  const AData: TsgInitMeshBuilderData;
  const ADeviationCoefficien: Double = 0.001);
var
  vParams: TsgDLLParam;
  vData: TsgConvertData;
  vData2: TsgFile3DVectFileData;
  vPContext: PsgContext;
begin
  vPContext := GetContext;
  if vPContext^.Context = nil then
  begin
    sgInitContext(vPContext);
  end;
  sgInitParser(vPContext, AInitParam);
  vData.File3DType := AData.File3DType;
  vData.File3DName := AData.File3DName;
  vData.IndexFaceMap := AData.IndexFaceMap;
  vData.Parser := AData.Self;
  vParams.GetTriangleFuncParam := AData.MeshParam;

  vData2.GetTriangleFunc := AData.TriangleFunc;
  vParams.GetTriangleFuncParam := AData.MeshParam;
  vData2.Params := @vParams;
  vData2.NewFaceGroupFunc := AData.NewFaceGroupFunc;
  vData2.BeginSegment := AData.BeginSegment;
  vData2.EndSegment := AData.EndSegment;

  sgFile3DVectFile(vPContext, vData, vData2);
end;

{ TsgBrepGroupChild }

procedure TsgBrepGroupChild.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgBrepGroupChild then
  begin
    Owner := TsgBrepGroupChild(Source).Owner;
  end;
end;

function TsgBrepGroupChild.GetContext: PsgContext;
begin
  Result := nil;
  if Assigned(Owner) then
    Result := Owner.GetContext;
end;

{ TsgBrepIges }

function TsgBrepIges.GetEntType: TsgCADEntities;
begin
  Result := ceIges;
end;

{ TsgBrepStep }

function TsgBrepStep.GetEntType: TsgCADEntities;
begin
  Result := ceStep;
end;

{ TsgBrepBrep }

function TsgBrepBrep.GetEntType: TsgCADEntities;
begin
  Result := ceBrep;
end;

{ TsgStackObject }

procedure TsgStackObject.Clear;
var
  I: Integer;
begin
  for I := 0 to Count - 1 do
    if List[I] <> nil then
      TsgDXFEntity(List[I]).Free;
  inherited Clear;
end;

function TsgStackObject.Pop: TsgDXFEntity;
begin
  Result := nil;
  if Count > 0 then
  begin
    Result := TsgDXFEntity(List[Count - 1]);
    Count := Count - 1;
  end;
end;

procedure TsgStackObject.Push(const AObject: TsgDXFEntity);
begin
  Add(Pointer(AObject));
end;

{ TsgDXFACISIndexFace }

procedure TsgDXFACISIndexFace.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFACISIndexFace then
  begin
    IndexFaceMap := TsgDXFACISIndexFace(Source).IndexFaceMap;
    Owner := TsgDXFACISIndexFace(Source).Owner;
  end;
end;

function TsgDXFACISIndexFace.GetEntType: TsgCADEntities;
begin
  Result := ce3DSolid;
end;

function TsgDXFACISIndexFace.GroupExists: Boolean;
begin
  Result := True;
end;

function TsgDXFACISIndexFace.GroupFill(AConverter: TsgDXFConverter): Boolean;
var
  vParams: PsgParamTriangle;
  vInitData: TsgInitMeshBuilderData;
begin
  New(vParams);
  try
    if vParams <> nil then
    begin
      SetParamsByMeshBuilder(vParams, @vInitData);
      vInitData.IndexFaceMap := IndexFaceMap;
      FOwner.GetMeshBrep(vInitData, AConverter.MeshQuality);
    end;
  finally
    Dispose(vParams);
  end;
  Result := GroupInternalEntities(AConverter);
end;

function TsgDXFACISIndexFace.GroupHasAddedEntities: Boolean;
begin
  Result := True;
end;

{ TsgFlatPoly3D }

procedure TsgFlatPoly3D.AddPoint(const X, Y, Z: Double);
var
  P: TFPoint;
begin
  P.X := X;
  P.Y := Y;
  P.Z := Z;
  TFPointList(FPoints).Add(P);
end;

function TsgFlatPoly3D.GetEntType: TsgCADEntities;
begin
  Result := ceFlatPoly3D;
end;

function TsgFlatPoly3D.GetPointsSignleList: TsgSingleList;
begin
  Result := nil;
end;

function TsgFlatPoly3D.GetPointsClass: TClass;
begin
  Result := TFPointList;
end;

function TsgFlatPoly3D.GetXY(Index: Integer): TFPoint;
begin
  Result := TFPointList(FPoints)[Index];
end;

function TsgFlatPoly3D.PCount: Integer;
begin
  Result := FPoints.Count;
end;

procedure TsgFlatPoly3D.SetXY(Index: Integer; const Value: TFPoint);
begin
  TFPointList(FPoints)[Index] := Value;
end;

{ TsgFlatBasePoly }

procedure TsgFlatPoly.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgFlatPoly then
    FLineWeight := TsgFlatPoly(Source).LineWeight;
end;

function TsgFlatPoly.GetLineWeight: Double;
begin
  Result := FLineWeight;
end;

function TsgFlatPoly.GetThickness: Double;
begin
  Result := LineWeight;
end;

function TsgFlatPoly.GroupFill(AConverter: TsgDXFConverter): Boolean;
var
  I, J, vCount, vIndex: Integer;
  vEntity: TsgDXFEntity;
  vVertex: TsgDXFVertex;
  vVertexes: TList;
  vPolyline3D: Boolean;

  procedure Loaded(E: TsgDXFEntity);
  begin
    E.Loaded(AConverter);
  end;

begin
  vVertexes := TList.Create;
  try
    vIndex := 0;
    for I := 0 to Counts.Count - 1 do
    begin
      vEntity := nil;
      vCount := Counts[I];
      if vCount > 2 then
      begin
        vPolyline3D := False;
        for J := vIndex to (vIndex + vCount - 1) do
        begin
          vVertex := TsgDXFVertex.Create;
          vVertex.Point := XY[J];
          Loaded(vVertex);
          vVertexes.Add(vVertex);
          if vVertex.Point.Z <> 0 then
            vPolyline3D := True;
        end;
        if vPolyline3D then
        begin
          vEntity := TsgDXFPolyline.Create;
          TsgDXFPolyline(vEntity).Polyline3D := True;
        end
        else
          vEntity := TsgDXFLWPolyline.Create;
        CopyLists(TsgDXFPolyline(vEntity).FEntities, vVertexes);
        // for J := 0 to vVertexes.Count - 1 do
        // vEntity.AddEntity(vVertexes[J]);
        vVertexes.Count := 0;
      end
      else if vCount = 2 then
      begin
        vEntity := TsgDXFLine.Create;
        TsgDXFLine(vEntity).Point := XY[vIndex];
        TsgDXFLine(vEntity).Point1 := XY[vIndex + 1];
      end;
      if vEntity <> nil then
      begin
        vEntity.AssignEntity(Self);
        Loaded(vEntity);
        Group.AddEntity(vEntity);
      end;
      Inc(vIndex, vCount);
    end;
    Result := Group.Count > 0;
  finally
    FreeList(vVertexes);
  end;
end;

procedure TsgFlatPoly.SetLineWeight(Value: Double);
begin
  FLineWeight := Value;
end;

{ TsgFlarEnity2D }

procedure TsgFlatEntity2D.AddPoint(const X, Y, Z: Double);
begin
  TsgSingleList(FPoints).Add(X);
  TsgSingleList(FPoints).Add(Y);
end;

function TsgFlatEntity2D.GetPointsSignleList: TsgSingleList;
begin
  Result := TsgSingleList(FPoints);
end;

function TsgFlatEntity2D.GetPointsClass: TClass;
begin
  Result := TsgSingleList;
end;

function TsgFlatEntity2D.GetXY(Index: Integer): TFPoint;
begin
  Inc(Index, Index);
  Result.X := TsgSingleList(FPoints)[Index];
  Result.Y := TsgSingleList(FPoints)[Index + 1];
  Result.Z := 0.0;
end;

function TsgFlatEntity2D.PCount: Integer;
begin
  Result := FPoints.Count div 2;
end;

procedure TsgFlatEntity2D.SetXY(Index: Integer; const Value: TFPoint);
var
  S: Single;
begin
  Inc(Index, Index);
  S := Value.X;
  TsgSingleList(FPoints)[Index] := S;
  S := Value.Y;
  TsgSingleList(FPoints)[Index + 1] := S;
end;

{ TsgDXFSectionTables }

constructor TsgDXFSectionTables.Create;
begin
  inherited Create;
  Name := cnstSectionTABLES;
end;

function TsgDXFSectionTables.IsTablesBelongSection
  (ATable: TConvSection): Boolean;
begin
  Result := False;
  case ATable of
    csLTypes, csLayers, csStyles, csDimStyles, csBlockRecords, csVPorts:
      Result := True;
  end;
end;

{ TsgDXFSectionObjects }

constructor TsgDXFSectionObjects.Create;
begin
  inherited Create;
  Name := cnstSectionOBJECTS;
end;

function TsgDXFSectionObjects.IsTablesBelongSection
  (ATable: TConvSection): Boolean;
begin
  Result := False;
  case ATable of
    csMLineStyles, csImageDefs, csLayouts, csTableStyles:
      Result := True;
  end;
end;

{ TsgLinkObject }

constructor TsgLinkObject.Create(const ALinkObjectData: TsgLinkObjectData);
begin
  Create;
  FData := ALinkObjectData;
end;

function TsgLinkObject.GetName: string;
begin
  Result := '';
  case FData.LinkType of
    lodtName:
      Result := string(FData.Name);
    lodtDimArrow:
      Result := sgDimensionArrowTypeNames[FData.ArrowType];
  end;
end;

function TsgLinkObject.GetObject(AOwner: TsgDXFEntity): TsgDXFEntity;
begin
  if not Assigned(FObject) and Assigned(AOwner) then
  begin
    case FData.LinkType of
      lodtName, lodtDimArrow:
        FObject := AOwner.FindEntByName(Name);
      lodtHandle:
        FObject := AOwner.FindEntByHandle(FData.Handle);
      lodtIndex:
        FObject := AOwner[FData.Index];
    end;
  end;
  Result := FObject;
end;

procedure TsgLinkObject.SetName(const AName: string);
begin
  FData.LinkType := lodtName;
  FData.Name := PChar(AName);
end;

constructor TsgLinkObject.Create(const AName: string);
begin
  Create;
  FData.LinkType := lodtName;
  FData.Name := PChar(AName);
end;

constructor TsgLinkObject.Create(const AHandle: UInt64;
  const ALinkType: TsgLinkObjectDataType);
begin
  Create;
  FData.LinkType := ALinkType;
  FData.Handle := AHandle;
end;

constructor TsgLinkObject.Create(const AArrowType: TsgDimArrowType);
begin
  Create;
  FData.LinkType := lodtDimArrow;
  FData.ArrowType := AArrowType;
end;

destructor TsgLinkObject.Destroy;
// var
// I: Integer;
// vEnt: TsgDXFEntity;
begin
  // for I := 0 to FRefs.Count - 1 do
  // begin
  // vEnt := FRefs[I];
  // if vEnt is TsgDXFDimensionStyle then
  // TsgDXFDimensionStyle(vEnt).ReplaceBlock(TsgDXFBlock(Self), TsgDXFBlock(FObject));
  // end;
  // FRefs.Free;
  inherited Destroy;
end;

constructor TsgLinkObject.Create;
begin
  // FRefs := TsgList.Create;
  // FRefs.Duplicates := dupIgnore;
  // FRefs.Sorted := True;
end;

{ TsgDXFSectionBlocks }

constructor TsgDXFSectionBlocks.Create;
begin
  inherited Create;
  Name := cnstSectionBLOCKS;
end;

{ TsgDXFDictionary }

function TsgDXFDictionary.GetValue: string;
begin
  Result := '';
end;

procedure TsgDXFDictionary.SetValue(const AValue: string);
begin
end;

{ TsgDXFInsertXRef }

procedure TsgDXFInsertXRef.LoadedInternal(AConverter: TsgDXFConverter);
var
  vCADFile: TsgCADImage;
  vPic: TPicture;
begin
  inherited LoadedInternal(AConverter);
  if FOwner = nil then
    Exit;
  vPic := TPicture.Create;
  try
    vPic.LoadFromFile(FNameFile);
    if not(vPic.Graphic is TsgCADImage) then
    begin
      Exit;
    end;
    vCADFile := TsgCADImageClass(vPic.Graphic.ClassType).Create;
    vCADFile.Assign(vPic.Graphic);
    FRealInsert := Converter.AddXRef(vCADFile, FNameFile, Point, Scale, Angle,
      TsgDXFLayout(FOwner));
  finally
    vPic.Free;
  end;
end;

{ TsgView }

procedure TsgView.PushView(const ARect: TRect);
begin
  if not Assigned(FStackView) then
    FStackView := TsgIntegerList.Create;
  if FStackView.Count > 1024 then
    FStackView.Delete(4, 4);
  FStackView.AppendArray([0, 0, 0, 0]);
  SetView(ARect);
end;

procedure TsgView.SetMatrix(const Value: TFMatrix);
begin
  FInternalFlags := FInternalFlags or 1;
  FMatrix := Value;
end;

procedure TsgView.SetView(const Value: TRect);
begin
  FStackView[FStackView.Count - 4] := Value.Left;
  FStackView[FStackView.Count - 3] := Value.Top;
  FStackView[FStackView.Count - 2] := Value.Bottom;
  FStackView[FStackView.Count - 1] := Value.Right;
end;

procedure TsgView.AssignEntity(Source: TsgDXFEntity);
var
  vView: TsgView absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgView then
  begin
    FInternalFlags := vView.FInternalFlags;
    FMatrix := vView.FMatrix;
    FreeAndNil(FStackView);
    if Assigned(vView.FStackView) then
    begin
      FStackView := TsgIntegerList.Create;
      FStackView.Assign(vView.FStackView);
    end;
  end;
end;

procedure TsgView.Clear(const ADoFree: Boolean = True);
begin
  FInternalFlags := 0;
  FMatrix := cnstIdentityMat;
  ClearView;
end;

procedure TsgView.ClearView;
begin;
  FreeAndNil(FStackView);
end;

constructor TsgView.Create;
begin
  inherited Create;
  Clear;
end;

procedure TsgView.FreeReferences;
begin
  inherited FreeReferences;
  ClearView;
end;

function TsgView.PopView: TRect;
begin
  if Assigned(FStackView) then
  begin
    Result := GetView;
    if FStackView.Count > 4 then
    begin
      FStackView.Count := FStackView.Count - 4;
      if FStackView.Count = 0 then
        FreeAndNil(FStackView);
    end;
  end
  else
    Result := cnstRectZero;
end;

function TsgView.GetView: TRect;
begin
  Result.Left := FStackView[FStackView.Count - 4];
  Result.Top := FStackView[FStackView.Count - 3];
  Result.Bottom := FStackView[FStackView.Count - 2];
  Result.Right := FStackView[FStackView.Count - 1];
end;

function TsgView.HasBaseView: Boolean;
begin
  Result := Assigned(FStackView);
end;

function TsgView.HasDrawMatrix: Boolean;
begin
  Result := FInternalFlags and 1 <> 0;
end;

function TsgView.HasView: Boolean;
begin
  Result := Assigned(FStackView) and (FStackView.Count > 4);
end;

{ TsgDXFSectionHeader }

constructor TsgDXFSectionHeader.CreateByConverter(const AConverter
  : TsgDXFConverter);
begin
  inherited CreateByConverter(AConverter);
  Name := cnstXMLNames[xmlHeader].Name;
  FAccess := TsgDXFEntitySample.Create;
  FAccess.Loaded(AConverter);
end;

destructor TsgDXFSectionHeader.Destroy;
begin
  FreeAndNil(FAccess);
end;

function TsgDXFSectionHeader.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
var
  vHeader: PsgHeadVarStruct;
  vLayout: TsgDXFLayout;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.Clear;
  vHeader := GetPHeadVarStruct(IsXMLHelp(AMode));
  if vHeader <> nil then
  begin
    ANode.AddAttribNV(cnstXMLNames[xmlName].Name).ValueAsStr := Name;
    ANode.AddAttribNV(cnstXMLNames[xmlACADVer].Name).ValueAsStr :=
      sgDWGVerToString(TsgDWGVersion(vHeader^.Version));
    ANode.AddAttribNV(cnstXMLNames[xmlCodePage].Name).ValueAsStr :=
      sgDXFCodePageName(vHeader^.CodePage);
    ANode.AddAttribNV(cnstXMLNames[xmlTextStyle].Name).ValueAsStr :=
      vHeader^.TextStyle;
    ANode.AddAttribNV(cnstXMLNames[xmlCLayer].Name).ValueAsStr :=
      vHeader^.CLayer;
    ANode.AddAttribNV(cnstXMLNames[xmlCELType].Name).ValueAsStr :=
      vHeader^.CELType;
    ANode.AddAttribNV(cnstXMLNames[xmlCEColor].Name).ValueData.ValueAsColorCAD
      := vHeader^.CEColor;
    ANode.AddAttribNV(cnstXMLNames[xmlCELTScale].Name).ValueAsDouble :=
      vHeader^.CELTScale;
    ANode.AddAttribNV(cnstXMLNames[xmlCELWeight].Name).ValueAsInt :=
      ConvertLineWeightToDXF(vHeader^.CELWeight);
    ANode.AddAttribNV(cnstXMLNames[xmlDimStyle].Name).ValueAsStr :=
      vHeader^.DimStyle;
    ANode.AddAttribNV(cnstXMLNames[xmlDimTextStyle].Name).ValueAsStr :=
      vHeader^.DimTextStyle;
    ToXMLNodeDimProps(vHeader^.DimProps, ANode, AMode);
    if IsEqualFPoints(vHeader^.ExtMim, vHeader^.ExtMax) and
      IsEqualFPoints(vHeader^.ExtMim, cnstFPointZero) and Assigned(FConverter)
      and (FConverter.GetLayoutsCount > 0) then
    begin
      vLayout := FConverter.Layouts[0];
      ANode.AddAttribNV(cnstXMLNames[xmlExtMim].Name).ValueAsFPoint :=
        MakeFPoint(vLayout.ExtMin.X, vLayout.ExtMax.Y);
      ANode.AddAttribNV(cnstXMLNames[xmlExtMax].Name).ValueAsFPoint :=
        MakeFPoint(vLayout.ExtMax.X, vLayout.ExtMin.Y);
    end
    else
    begin
      ANode.AddAttribNV(cnstXMLNames[xmlExtMim].Name).ValueAsFPoint :=
        vHeader^.ExtMim;
      ANode.AddAttribNV(cnstXMLNames[xmlExtMax].Name).ValueAsFPoint :=
        vHeader^.ExtMax;
    end;
    ANode.AddAttribNV(cnstXMLNames[xmlFilletRadius].Name).ValueAsDouble :=
      vHeader^.FilletRadius;
    ANode.AddAttribNV(cnstXMLNames[xmlInsUnits].Name).ValueAsInt :=
      vHeader^.InsUnits;
    ANode.AddAttribNV(cnstXMLNames[xmlLTScale].Name).ValueAsDouble :=
      vHeader^.LTScale;
    ANode.AddAttribNV(cnstXMLNames[xmlMeasurement].Name).ValueAsInt :=
      Ord(vHeader^.Measurement);
    ANode.AddAttribNV(cnstXMLNames[xmlPointDisplayMode].Name).ValueAsInt :=
      Ord(vHeader^.PointDisplayMode);
    ANode.AddAttribNV(cnstXMLNames[xmlPointDisplaySize].Name).ValueAsDouble :=
      vHeader^.PointDisplaySize;
    ANode.AddAttribNV(cnstXMLNames[xmlTextSize].Name).ValueAsDouble :=
      vHeader^.TextSize;
    ANode.AddAttribNV(cnstXMLNames[xmlTileMode].Name).ValueAsInt :=
      vHeader^.TileMode;
    ANode.AddAttribNV(cnstXMLNames[xmlUCSORG].Name).ValueAsFPoint :=
      vHeader^.UCSORG;
    ANode.AddAttribNV(cnstXMLNames[xmlUCSXDir].Name).ValueAsFPoint :=
      vHeader^.UCSXDir;
    ANode.AddAttribNV(cnstXMLNames[xmlUCSYDir].Name).ValueAsFPoint :=
      vHeader^.UCSYDir;
    ANode.AddAttribNV(cnstXMLNames[xmlInsBase].Name).ValueAsFPoint :=
      vHeader^.InsBase;
    ANode.AddAttribNV(cnstXMLNames[xmlAttributeMode].Name).ValueAsInt :=
      Ord(vHeader^.AttMode);
  end;
end;

class function TsgDXFSectionHeader.ToXMLNodeDimProps(const AProps: TsgDimStyle;
  const ANode: TsgNode; const AMode: TsgXMLModes): Integer;
begin
  Result := cnstXML_OK;
  ANode.AddAttribNV(cnstXMLNames[xmlDimAlt].Name).ValueAsBool := AProps.Alt;
  ANode.AddAttribNV(cnstXMLNames[xmlDimAltF].Name).ValueAsDouble := AProps.AltF;
  ANode.AddAttribNV(cnstXMLNames[xmlDimAPost].Name).ValueAsStr := AProps.APost;
  ANode.AddAttribNV(cnstXMLNames[xmlDimAsz].Name).ValueAsDouble := AProps.Asz;
  ANode.AddAttribNV(cnstXMLNames[xmlDimSah].Name).ValueAsBool := AProps.Sah;
  ANode.AddAttribNV(cnstXMLNames[xmlDimCen].Name).ValueAsDouble := AProps.Cen;
  ANode.AddAttribNV(cnstXMLNames[xmlDimClrD].Name).ValueData.ValueAsColorCAD :=
    AProps.ClrD;
  ANode.AddAttribNV(cnstXMLNames[xmlDimClrE].Name).ValueData.ValueAsColorCAD :=
    AProps.ClrE;
  ANode.AddAttribNV(cnstXMLNames[xmlDimClrT].Name).ValueData.ValueAsColorCAD :=
    AProps.ClrT;
  ANode.AddAttribNV(cnstXMLNames[xmlDimSD1].Name).ValueAsBool := AProps.SD1;
  ANode.AddAttribNV(cnstXMLNames[xmlDimSD2].Name).ValueAsBool := AProps.SD2;
  ANode.AddAttribNV(cnstXMLNames[xmlDimSE1].Name).ValueAsBool := AProps.SE1;
  ANode.AddAttribNV(cnstXMLNames[xmlDimSE2].Name).ValueAsBool := AProps.SE2;
  ANode.AddAttribNV(cnstXMLNames[xmlDimDec].Name).ValueAsInt := AProps.Dec;
  ANode.AddAttribNV(cnstXMLNames[xmlDimExe].Name).ValueAsDouble := AProps.Exe;
  ANode.AddAttribNV(cnstXMLNames[xmlDimExo].Name).ValueAsDouble := AProps.Exo;
  ANode.AddAttribNV(cnstXMLNames[xmlDimGap].Name).ValueAsDouble := AProps.GAP;
  ANode.AddAttribNV(cnstXMLNames[xmlDimLFac].Name).ValueAsDouble := AProps.LFac;
  ANode.AddAttribNV(cnstXMLNames[xmlDimLwD].Name).ValueAsDouble := AProps.LwD;
  ANode.AddAttribNV(cnstXMLNames[xmlDimLwE].Name).ValueAsDouble := AProps.LwE;
  ANode.AddAttribNV(cnstXMLNames[xmlDimPost].Name).ValueAsStr := AProps.Post;
  ANode.AddAttribNV(cnstXMLNames[xmlDimScale].Name).ValueAsDouble :=
    AProps.Scale;
  ANode.AddAttribNV(cnstXMLNames[xmlDimTad].Name).ValueAsInt := AProps.Tad;
  ANode.AddAttribNV(cnstXMLNames[xmlDimTih].Name).ValueAsBool := AProps.Tih;
  ANode.AddAttribNV(cnstXMLNames[xmlDimTix].Name).ValueAsInt := AProps.Tix;
  ANode.AddAttribNV(cnstXMLNames[xmlDimToh].Name).ValueAsBool := AProps.Toh;
  ANode.AddAttribNV(cnstXMLNames[xmlDimTxt].Name).ValueAsDouble := AProps.Txt;
end;

function TsgDXFSectionHeader.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  vIntVal: Integer;
  vDoubleVal: TsgFloat;
  vStrVal: string;
  vDXFTable: TsgDXFTable;
  vStyle: TsgDXFStyle;
  vDimStyle: TsgDXFDimensionStyle;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlACADVer:
      begin
      end; // ANode.ValueAsStr := sgDWGVerToString(TsgDWGVersion(FConverter.GetPHeadVarStruct^.Version));
    xmlCodePage:
      begin
      end; // ANode.ValueAsStr := sgDXFCodePageName(FConverter.GetPHeadVarStruct^.CodePage);
    xmlTextStyle, xmlCLayer, xmlCELType:
      begin
        vStrVal := ANode.ValueAsStr;
        case AType.ID of
          xmlTextStyle:
            vDXFTable := FConverter.FStyles;
          xmlCLayer:
            vDXFTable := FConverter.FLayers;
          xmlCELType:
            vDXFTable := FConverter.FLTypes;
        else
          vDXFTable := nil;
        end;
        if Assigned(vDXFTable) and Assigned(vDXFTable.FindEntByName(vStrVal))
        then
          case AType.ID of
            xmlTextStyle:
              FConverter.GetPHeadVarStruct^.TextStyle := vStrVal;
            xmlCLayer:
              FConverter.GetPHeadVarStruct^.CLayer := vStrVal;
            xmlCELType:
              FConverter.GetPHeadVarStruct^.CELType := vStrVal;
          end
        else
          Result := cnstXML_ERROR;
      end;
    xmlCEColor:
      FConverter.GetPHeadVarStruct^.CEColor := ANode.ValueData.ValueAsColorCAD;
    xmlDimStyle:
      begin
        vStrVal := ANode.ValueAsStr;
        vDimStyle := TsgDXFDimensionStyle(FConverter.Sections[csDimStyles]
          .FindEntByName(vStrVal));
        if Assigned(vDimStyle) then
        begin
          FAccess.DimStyle := vDimStyle;
          // FConverter.GetPHeadVarStruct^.DimStyle := vStrVal;
        end
        else
          Result := cnstXML_ERROR;
      end;
    xmlDimTextStyle:
      begin
        vStrVal := ANode.ValueAsStr;
        vStyle := TsgDXFStyle(FConverter.Sections[csStyles].FindEntByName
          (vStrVal));
        if Assigned(vStyle) then
        begin
          FAccess.DimStyle.TextStyle := vStyle;
          FConverter.GetPHeadVarStruct^.DimTextStyle := vStrVal;
        end
        else
          Result := cnstXML_ERROR;
      end;
    xmlCELWeight:
      begin
        if TryStrToInt(ANode.ValueAsStr, vIntVal) then
        begin
          if ConvertDXFToLineWeight(vIntVal, vDoubleVal) then
            FConverter.GetPHeadVarStruct^.CELWeight := vDoubleVal
          else
            Result := cnstXML_ERROR;
        end
        else
          Result := cnstXML_ERROR;
      end;
    xmlExtMim:
      FConverter.GetPHeadVarStruct^.ExtMim := ANode.ValueAsFPoint;
    xmlExtMax:
      FConverter.GetPHeadVarStruct^.ExtMax := ANode.ValueAsFPoint;
    xmlCELTScale, xmlFilletRadius, xmlLTScale, xmlPointDisplaySize, xmlTextSize:
      begin
        if TryStrToFloat(ANode.ValueAsStr, vDoubleVal) then
          case AType.ID of
            xmlCELTScale, xmlLTScale:
              if vDoubleVal > 0 then
                case AType.ID of
                  xmlCELTScale:
                    FConverter.GetPHeadVarStruct^.CELTScale := vDoubleVal;
                  xmlLTScale:
                    FConverter.GetPHeadVarStruct^.LTScale := vDoubleVal;
                end
              else
                Result := cnstXML_ERROR;
            xmlFilletRadius:
              FConverter.GetPHeadVarStruct^.FilletRadius := vDoubleVal;
            xmlPointDisplaySize:
              FConverter.GetPHeadVarStruct^.PointDisplaySize := vDoubleVal;
            xmlTextSize:
              FConverter.GetPHeadVarStruct^.TextSize := vDoubleVal;
          end
        else
          Result := cnstXML_ERROR;
      end;
    xmlMeasurement:
      FConverter.GetPHeadVarStruct^.Measurement := Boolean(ANode.ValueAsInt);
    xmlInsUnits, xmlPointDisplayMode, xmlTileMode:
      begin
        if TryStrToInt(ANode.ValueAsStr, vIntVal) then
          case AType.ID of
            xmlInsUnits:
              begin
                if (vIntVal >= 0) and (vIntVal <= 20) then
                  FConverter.GetPHeadVarStruct^.InsUnits := vIntVal
                else
                  Result := cnstXML_ERROR;
              end;
            xmlPointDisplayMode:
              case vIntVal of
                0 .. 4, 32 .. 36, 64 .. 68, 96 .. 100:
                  FConverter.GetPHeadVarStruct^.PointDisplayMode := vIntVal;
              else
                Result := cnstXML_ERROR;
              end;
            xmlTileMode:
              FConverter.GetPHeadVarStruct^.TileMode := vIntVal;
          end
        else
          Result := cnstXML_ERROR;
      end;
    xmlUCSORG:
      FConverter.GetPHeadVarStruct^.UCSORG := ANode.ValueAsFPoint;
    xmlUCSXDir:
      FConverter.GetPHeadVarStruct^.UCSXDir := ANode.ValueAsFPoint;
    xmlUCSYDir:
      FConverter.GetPHeadVarStruct^.UCSYDir := ANode.ValueAsFPoint;
    xmlInsBase:
      FConverter.GetPHeadVarStruct^.InsBase := ANode.ValueAsFPoint;
    xmlAttributeMode:
      FConverter.GetPHeadVarStruct^.AttMode :=
        TsgAttributeMode(ANode.ValueAsInt);
  else
    Result := cnstXML_UNSUPPORTED;
  end;
  if Result = cnstXML_UNSUPPORTED then
  begin
    Result := FromXMLNodeDimProps(FConverter.GetPHeadVarStruct^.DimProps, AType,
      ANode, AIsChild, AResult);
    FAccess.DimStyle.UpdateDimProps(FConverter.GetPHeadVarStruct^.DimProps);
  end;
end;

class function TsgDXFSectionHeader.FromXMLNodeDimProps(var AProps: TsgDimStyle;
  const AType: TsgXMLType; const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  vDoubleValue: Double;
  vIntegerValue: Integer;
  vBooleanValue, vIsSet: Boolean;
  vStrValue: string;
begin
  Result := cnstXML_OK;
  case AType.ID of
    xmlDimAltF, xmlDimAsz, xmlDimCen, xmlDimExe, xmlDimExo, xmlDimGap,
      xmlDimLFac, xmlDimLwD, xmlDimLwE, xmlDimScale, xmlDimTxt:
      begin
        if TryStrToFloat(ANode.ValueAsStr, vDoubleValue) then
        begin
          case AType.ID of
            xmlDimAltF:
              AProps.AltF := vDoubleValue;
            xmlDimAsz:
              begin
                if vDoubleValue >= 0 then
                  AProps.Asz := vDoubleValue
                else
                  Result := cnstXML_ERROR;
              end;
            xmlDimCen:
              AProps.Cen := vDoubleValue;
            xmlDimExe:
              begin
                if vDoubleValue >= 0 then
                  AProps.Exe := vDoubleValue
                else
                  Result := cnstXML_ERROR;
              end;
            xmlDimExo:
              begin
                if vDoubleValue >= 0 then
                  AProps.Exo := vDoubleValue
                else
                  Result := cnstXML_ERROR;
              end;
            xmlDimGap:
              AProps.GAP := vDoubleValue;
            xmlDimLFac:
              AProps.LFac := vDoubleValue;
            xmlDimLwD:
              AProps.LwD := vDoubleValue;
            xmlDimLwE:
              AProps.LwE := vDoubleValue;
            xmlDimScale:
              AProps.Scale := vDoubleValue;
            xmlDimTxt:
              AProps.Txt := vDoubleValue;
          end;
        end
        else
          Result := cnstXML_ERROR;
      end;
    xmlDimDec, xmlDimTad, xmlDimTix:
      begin
        if TryStrToInt(ANode.ValueAsStr, vIntegerValue) then
          case AType.ID of
            xmlDimDec:
              begin
                if (vIntegerValue >= 0) and (vIntegerValue <= 8) then
                  AProps.Dec := vIntegerValue
                else
                  Result := cnstXML_ERROR;
              end;
            xmlDimTad:
              AProps.Tad := vIntegerValue;
            xmlDimTix:
              AProps.Tix := vIntegerValue;
          end
        else
          Result := cnstXML_ERROR;
      end;

    xmlDimAlt, xmlDimSah, xmlDimSD1, xmlDimSD2, xmlDimSE1, xmlDimSE2, xmlDimTih,
      xmlDimToh:
      begin
        vStrValue := ANode.ValueAsStr;
        vIsSet := False;
        if not TryStrToBool(vStrValue, vBooleanValue) then
        begin
          if TryStrToInt(vStrValue, vIntegerValue) then
            if vIntegerValue in [0, 1] then
            begin
              vBooleanValue := vIntegerValue = 1;
              vIsSet := True;
            end;
        end
        else
          vIsSet := True;
        if vIsSet then
        begin
          case AType.ID of
            xmlDimAlt:
              AProps.Alt := vBooleanValue;
            xmlDimSah:
              AProps.Sah := vBooleanValue;
            xmlDimSD1:
              AProps.SD1 := vBooleanValue;
            xmlDimSD2:
              AProps.SD2 := vBooleanValue;
            xmlDimSE1:
              AProps.SE1 := vBooleanValue;
            xmlDimSE2:
              AProps.SE2 := vBooleanValue;
            xmlDimTih:
              AProps.Tih := vBooleanValue;
            xmlDimToh:
              AProps.Toh := vBooleanValue;
          end;
        end
        else
          Result := cnstXML_ERROR;
      end;

    xmlDimAPost:
      AProps.APost := ANode.ValueAsStr;
    xmlDimClrD:
      AProps.ClrD := ANode.ValueData.ValueAsColorCAD;
    xmlDimClrE:
      AProps.ClrE := ANode.ValueData.ValueAsColorCAD;
    xmlDimClrT:
      AProps.ClrT := ANode.ValueData.ValueAsColorCAD;
    xmlDimPost:
      AProps.Post := ANode.ValueAsStr;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgDXFSectionHeader.GetPHeadVarStruct(const AGetDefault
  : Boolean = True): PsgHeadVarStruct;
begin
  if AGetDefault then
    Result := @cnstDefHeadVarStruct
  else
    Result := nil;
  if Assigned(FConverter) then
    Result := FConverter.PHeadVarStruct;
end;

{ TsgDXFSectionForXMLExport }

function TsgDXFSectionForXMLExport.AddItem(const AItem: TsgDXFEntity): Integer;
begin
  Result := -1;
end;

constructor TsgDXFSectionForXMLExport.CreateByConverter(const AConverter
  : TsgDXFConverter);
begin
  inherited Create;
  SetConverter(AConverter);
end;

function TsgDXFSectionForXMLExport.DeleteItem(const AItem
  : TsgDXFEntity): Integer;
begin
  Result := -1;
end;

function TsgDXFSectionForXMLExport.FindEntByName(const AName: string)
  : TsgDXFEntity;
var
  I: Integer;
begin
  Result := nil;
  I := IndexOfName(AName);
  if I >= 0 then
    Result := Entities[I];
end;

procedure TsgDXFSectionForXMLExport.Link(AConverter: TsgDXFConverter);
begin
  // for do not use sortlist
  SetConverter(AConverter);
end;

{ TsgEvacuationDefault }

procedure TsgEvacuationDefault.AssignEntity(Source: TsgDXFEntity);
var
  vDefault: TsgEvacuationDefault absolute Source;
begin
  inherited AssignEntity(Source);
  if Source is TsgEvacuationDefault then
  begin
    FPathEvacucationColor := vDefault.FPathEvacucationColor;
    FPathEvacucationWidth := vDefault.FPathEvacucationWidth;
    FPathEvacucationLineTypeScale := vDefault.FPathEvacucationLineTypeScale;
  end;
end;

constructor TsgEvacuationDefault.Create;
begin
  inherited Create;
  FPathEvacucationColor := cnstColorCADByPathEvacuation;
  FPathEvacucationLineTypeScale := 1;
  FPathEvacucationWidth := 0.18;
end;

function TsgEvacuationDefault.GetPathEvacColor: TsgColorCAD;
begin
  Result := FPathEvacucationColor;
end;

function TsgEvacuationDefault.GetPathEvacLayer: string;
begin
  Result := sLayerPathEvacuation;
end;

function TsgEvacuationDefault.GetPathEvacLineTypeScale: Double;
begin
  Result := FPathEvacucationLineTypeScale;
end;

function TsgEvacuationDefault.GetPathEvacWidth: Double;
begin
  Result := FPathEvacucationWidth;
end;

procedure TsgEvacuationDefault.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
end;

procedure TsgEvacuationDefault.SetPathEvacColor(const Value: TsgColorCAD);
begin
  FPathEvacucationColor := Value;
end;

procedure TsgEvacuationDefault.SetPathEvacLineTypeScale(const Value: Double);
begin
  if Value <> 0 then
    FPathEvacucationLineTypeScale := Value;
end;

procedure TsgEvacuationDefault.SetPathEvacWidth(const Value: Double);
begin
  FPathEvacucationWidth := Value;
end;

{ TsgDXFEntitySampleCustom }

procedure TsgDXFEntitySampleCustom.AfterChange(const AType: TsgPropertyType);
begin
  if Assigned(FOnAfterChange) then
    FOnAfterChange(Self, AType);
end;

procedure TsgDXFEntitySampleCustom.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFEntitySampleCustom then
    SetConverter(TsgDXFEntitySampleCustom(Source).FConverter);
end;

procedure TsgDXFEntitySampleCustom.BeforeChange(const AType: TsgPropertyType);
begin
  if Assigned(FOnBeforeChange) then
    FOnBeforeChange(Self, AType);
end;

constructor TsgDXFEntitySampleCustom.Create;
begin
  inherited Create;
end;

function TsgDXFEntitySampleCustom.GetActiveHeadVar: PsgHeadVarStruct;
begin
  if FConverter <> nil then
    Result := @FConverter.FHeadVarStruct
  else
    Result := @cnstSGHeadVarStruct
end;

function TsgDXFEntitySampleCustom.GetConverter: TsgDXFConverter;
begin
  Result := FConverter;
end;

procedure TsgDXFEntitySampleCustom.LoadedInternal(AConverter: TsgDXFConverter);
begin
  inherited LoadedInternal(AConverter);
end;

procedure TsgDXFEntitySampleCustom.SetConverter(const AConverter
  : TsgDXFConverter);
begin
{$IFDEF CONV_REFCOUNT}
  if FConverter <> AConverter then
  begin
    if Assigned(FConverter) then
      Dec(FConverter.FRefCount);
{$ENDIF}
    FConverter := AConverter;
{$IFDEF CONV_REFCOUNT}
    if Assigned(FConverter) then
      Inc(FConverter.FRefCount);
  end;
{$ENDIF}
end;

{ TsgCADBoundaryData }

function TsgCADBoundaryData.AddBoundaryList(const AFlags: Byte)
  : Tsg2DBoundaryList;
begin
  Result := Tsg2DBoundaryList.Create;
  FBoundaries.Add(Result);
  Result.BoundaryType := AFlags;
end;

procedure TsgCADBoundaryData.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgCADBoundaryData then
  begin
    ClearBoundaries;
    CopyBoundaries(TsgCADBoundaryData(Source));
  end;
end;

function TsgCADBoundaryData.BoundaryToFromNode(const ABoundary
  : Tsg2DBoundaryList; const ANode: TsgNodeSample;
  const AResult: IsgResultNode = nil): Integer;
var
  I: Integer;
  vFlags, vChild: TsgNodeSample;
  vObjectClass: TsgObjectClass;
  vCurve: Tsg2DCurve;
begin
  Result := cnstXML_OK;
  vFlags := ANode.GetAttributeByName(cnstXMLNames[xmlFlags].Name);
  if Assigned(vFlags) then
    ABoundary.BoundaryType := vFlags.ValueAsInt;
  for I := 0 to ANode.ChildNodesCount - 1 do
  begin
    vChild := ANode.ChildNodes[I];
    vObjectClass := TsgObjectClass(GetClassByXMLName(vChild.Name));
    if Assigned(vObjectClass) then
    begin
      vCurve := Tsg2DCurve(vObjectClass.Create);
      ABoundary.Add(vCurve);
      vCurve.FromXML(vChild, AResult);
    end;
  end;
end;

function TsgCADBoundaryData.BoundaryToXMLNode(const ABoundary
  : Tsg2DBoundaryList; const ANode: TsgNode): Integer;
var
  I: Integer;
begin
  Result := cnstXML_OK;
  ANode.AddAttribNV(cnstXMLNames[xmlFlags].Name).ValueAsInt :=
    ABoundary.BoundaryType;
  for I := 0 to ABoundary.Count - 1 do
    ABoundary[I].ToXML(ANode);
end;

function TsgCADBoundaryData.CanUseBoundaryList(const AList: Tsg2DBoundaryList;
  const ASolidFill: Boolean): Boolean;

  function IsNotUse(ABoundaryType: Byte): Boolean;
  begin
    Result := ((ABoundaryType > 31) and (ABoundaryType and 4 = 0) and
      ASolidFill) or (ABoundaryType and 128 <> 0);
    // The are files, where 8'th or 6'th bits are set
  end;

begin
  Result := (AList.Count > 0) and (not IsNotUse(AList.BoundaryType));
end;

procedure TsgCADBoundaryData.ClearBoundaries(const AClearCapacity: Boolean);
begin
  ClearList(FBoundaries, AClearCapacity);
end;

procedure TsgCADBoundaryData.ClearReferences;
begin
  inherited ClearReferences;
  ClearBoundaries;
end;

procedure TsgCADBoundaryData.CopyBoundaries(const ABoundaryData
  : TsgCADBoundaryData);
var
  I: Integer;
  L: TObject;
  LNew: Tsg2DBoundaryList;
begin
  FBoundaries.Capacity := ABoundaryData.FBoundaries.Count;
  for I := 0 to ABoundaryData.FBoundaries.Count - 1 do
  begin
    L := ABoundaryData.FBoundaries.Items[I];
    if L = nil then
      Continue;
    if ((L is Tsg2DBoundaryList) and (Tsg2DBoundaryList(L).Count > 0)) or
      ((L is TList) and (TList(L).Count > 0)) then
    begin
      LNew := Tsg2DBoundaryList.Create;
      FBoundaries.Add(LNew);
      LNew.AssignBoundary(L);
    end;
  end;
end;

constructor TsgCADBoundaryData.Create;
begin
  inherited Create;
  FBoundaries := TList.Create;
end;

procedure TsgCADBoundaryData.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FBoundaries);
end;

function TsgCADBoundaryData.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  vBoundary: Tsg2DBoundaryList;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlBoundary:
      begin
        vBoundary := Tsg2DBoundaryList.Create;
        FBoundaries.Add(vBoundary);
        BoundaryToFromNode(vBoundary, ANode, AResult);
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgCADBoundaryData.GenerateListOfBoundaries(const AList: TList;
  AExplodePolyline: Boolean = False): TFRect;
var
  I, Cnt{$IFDEF SG_BTI}, J{$ENDIF}: Integer;
  vEnt{$IFDEF SG_BTI}, vEntSub{$ENDIF}: TsgDXFEntity;
  vOnlyPoly: Boolean;
  vActBoundary: Tsg2DBoundaryList;

  function GetActBoundary(const APoly: TsgCADBasePolyline): Tsg2DBoundaryList;
  begin
    if APoly.Closed then
      Result := AddBoundaryList(1)
    else
    begin
      if vActBoundary = nil then
        vActBoundary := AddBoundaryList(1);
      Result := vActBoundary;
    end;
  end;

  procedure AddHatchOfArc(AArc: TsgDXFArc);
  var
    vArc: Tsg2DArc;
    vBoundaryList: Tsg2DBoundaryList;
  begin
    vBoundaryList := GetActBoundary(AArc);
    vArc := Tsg2DArc.Create;
    vBoundaryList.Add(vArc);
    vArc.CenterPoint := MakeF2DPoint(AArc.Point.X, AArc.Point.Y);
    vArc.Radius := AArc.Radius;
    vArc.StartParam := AArc.StartAngle;
    vArc.EndParam := AArc.EndAngle;
    vArc.CounterClockWise := True;
    UnionFRect(Result, vEnt.Box);
  end;

  procedure AddHatchOfCircle(ACircle: TsgDXFCircle);
  var
    vCircle: Tsg2DArc;
    vBoundaryList: Tsg2DBoundaryList;
  begin
    vBoundaryList := GetActBoundary(ACircle);
    vCircle := Tsg2DArc.Create;
    vBoundaryList.Add(vCircle);
    vCircle.CenterPoint := MakeF2DPoint(ACircle.Point.X, ACircle.Point.Y);
    vCircle.Radius := ACircle.Radius;
    vCircle.StartParam := 0;
    vCircle.EndParam := 360;
    vCircle.CounterClockWise := True;
    UnionFRect(Result, vEnt.Box);
  end;

  procedure AddHatchOfEllipse(AEllipse: TsgDXFEllipse);
  var
    vEllipse: Tsg2DEllipse;
    vBoundaryList: Tsg2DBoundaryList;
  begin
    vBoundaryList := GetActBoundary(AEllipse);
    vEllipse := Tsg2DEllipse.Create;
    vBoundaryList.Add(vEllipse);
    vEllipse.CenterPoint := MakeF2DPoint(AEllipse.Point.X, AEllipse.Point.Y);
    vEllipse.MajorPoint := MakeF2DPoint(AEllipse.EndPoint.X,
      AEllipse.EndPoint.Y);
    vEllipse.Radius := AEllipse.Ratio;
    vEllipse.StartParam := AEllipse.StartAngle;
    vEllipse.EndParam := AEllipse.EndAngle;
    vEllipse.IsAngleInParam := False;
    vEllipse.CounterClockWise := True;
    UnionFRect(Result, vEnt.Box);
  end;

  procedure AddHatchOfLine(ALine: TsgDXFLine);
  var
    vLine: Tsg2DLine;
  begin
    if vActBoundary = nil then
      vActBoundary := AddBoundaryList(1);
    vLine := Tsg2DLine.Create;
    vActBoundary.Add(vLine);
    vLine.SetStartPoint(MakeF2DPoint(ALine.Point.X, ALine.Point.Y));
    vLine.SetEndPoint(MakeF2DPoint(ALine.Point1.X, ALine.Point1.Y));
    UnionFRect(Result, vEnt.Box);
  end;

  procedure AddHatchOfPolyBezier(ASpline: TsgDXFSpline);
  var
    I, Cnt: Integer;
    vSpline: Tsg2DSpline;
    vLine: Tsg2DLine;
    vBoundaryList: Tsg2DBoundaryList;
  begin
    vBoundaryList := GetActBoundary(ASpline);
    if ASpline.IsByAngles then
    begin
      Cnt := ASpline.PointCount - 1;
      if Cnt > 1 then
      begin
        for I := 1 to Cnt do
        begin
          vLine := Tsg2DLine.Create;
          vBoundaryList.Add(vLine);
          vLine.SetStartPoint(MakeF2DPointFrom3D(ASpline.PolyPoints[I - 1]));
          vLine.SetEndPoint(MakeF2DPointFrom3D(ASpline.PolyPoints[I]));
        end;
        if ASpline.Closed then
        begin
          vLine := Tsg2DLine.Create;
          vBoundaryList.Add(vLine);
          vLine.SetStartPoint(MakeF2DPointFrom3D(ASpline.PolyPoints[0]));
          vLine.SetEndPoint(MakeF2DPointFrom3D(ASpline.PolyPoints[Cnt]));
        end;
      end;
    end
    else
    begin
      vSpline := Tsg2DSpline.Create;
      vBoundaryList.Add(vSpline);
      vSpline.Degree := ASpline.Degree;
      Cnt := ASpline.Controls.Count - 1;
      for I := 0 to Cnt do
        vSpline.AddControl(MakeF2DPointFrom3D(ASpline.Controls[I]));
      Cnt := ASpline.Knots.Count - 1;
      for I := 0 to Cnt do
        vSpline.AddKnot(ASpline.Knots[I]);
    end;
    UnionFRect(Result, vEnt.Box);
  end;

  procedure AddHatchOfPolyline(APoly: TsgDXFPolyline);
  var
    I, Cnt: Integer;
    vPoly: Tsg2DPolyline;
    vLine: Tsg2DLine;
    vVertex: TsgDXFVertex;
    vTP: TF2DPoint;
    vBoundaryList: Tsg2DBoundaryList;
    vPoint, vPointNew: TFPoint;
  begin
    if (vOnlyPoly and not AExplodePolyline) or APoly.Closed then
    begin
      vBoundaryList := AddBoundaryList(7);
      vPoly := Tsg2DPolyline.Create;
      vBoundaryList.Add(vPoly);
      Cnt := APoly.Count - 1;
      for I := 0 to Cnt do
      begin
        vVertex := TsgDXFVertex(APoly.Entities[I]);
        vTP.X := vVertex.Point.X;
        vTP.Y := vVertex.Point.Y;
        if (I > 0) and IsEqualF2DPoints(vTP, vPoly.EndPoint) then
          Continue;
        vPoly.AddVertex(vTP);
        if Abs(vVertex.Bulge) > fAccuracy then
          vPoly.AddBulge(vVertex.Bulge);
      end;
      vPoly.Closed := not IsEqualF2DPoints(vPoly.StartPoint, vPoly.EndPoint);
      UnionFRect(Result, vEnt.Box);
    end
    else
    begin
      if APoly.PolyPoints.Count > 1 then
      begin
        if vActBoundary = nil then
          vActBoundary := AddBoundaryList(1);
        Cnt := APoly.PolyPoints.Count - 1;
        vPoint := APoly.PolyPoints.List[0];
        for I := 1 to Cnt do
        begin
          vPointNew := APoly.PolyPoints.List[I];
          if not IsEqualFPoints2D(vPoint, vPointNew) then
          begin
            vLine := Tsg2DLine.Create;
            vActBoundary.Add(vLine);
            vLine.SetStartPoint(MakeF2DPoint(vPoint.X, vPoint.Y));
            vLine.SetEndPoint(MakeF2DPoint(vPointNew.X, vPointNew.Y));
            vPoint := vPointNew;
          end;
        end;
        UnionFRect(Result, vEnt.Box);
      end;
    end;
  end;

begin
  Cnt := AList.Count - 1;
  ClearBoundaries(False);
  FBoundaries.Capacity := AList.Count;
  Result := cnstBadRect;
  vOnlyPoly := True;
  vActBoundary := nil;
  for I := 0 to Cnt do
  begin
    vEnt := AList.List[I];
    if (vEnt <> nil) and (not(vEnt.EntType in [cePolyline, ceLWPolyline])) then
    begin
      vOnlyPoly := False;
      Break;
    end;
  end;
  for I := 0 to Cnt do
  begin
    vEnt := AList[I];
    if vEnt <> nil then
    begin
      case vEnt.EntType of
        ceArc:
          AddHatchOfArc(TsgDXFArc(vEnt));
        ceCircle:
          AddHatchOfCircle(TsgDXFCircle(vEnt));
        ceEllipse:
          AddHatchOfEllipse(TsgDXFEllipse(vEnt));
        ceLine:
          AddHatchOfLine(TsgDXFLine(vEnt));
        cePolyline:
          AddHatchOfPolyline(TsgDXFPolyline(vEnt));
        ceLWPolyline:
          AddHatchOfPolyline(TsgDXFPolyline(vEnt));
        ceSpline:
          AddHatchOfPolyBezier(TsgDXFSpline(vEnt));
{$IFDEF SG_BTI}
        ceInsert:
          begin
            case vEnt.GetEntTypeEx of
              cnstArea, cnstComplexArea:
                begin
                  if TsgDXFInsert(vEnt).Block <> nil then
                  begin
                    for J := 0 to TsgDXFInsert(vEnt).Block.Count - 1 do
                    begin
                      vEntSub := TsgDXFInsert(vEnt).Block.Entities[J];
                      if vEntSub.EntType in [ceLWPolyline, cePolyline] then
                        AddHatchOfPolyline(TsgDXFPolyline(vEntSub));
                    end;
                  end;
                end;
            end;
          end;
{$ENDIF}
      end;
    end
    else
      vActBoundary := nil;
  end;
end;

function TsgCADBoundaryData.GetIndexOfNeighbour(const AList: Tsg2DBoundaryList;
  const ALastPoint: TF2DPoint; const AStartIndex: Integer;
  const AAccuracy: Double; var ALastPointType: Boolean): Integer;
var
  J, vIndexD: Integer;
  vDistance: array [0 .. 1] of Extended;
  vAccuracy: Extended;
  vHatchSegment: Tsg2DCurve;
begin
  vAccuracy := Sqr(AAccuracy);
  Result := -1;
  for J := AStartIndex + 1 to AList.Count - 1 do
  begin
    vHatchSegment := AList[J];
    vDistance[0] := DistanceF2DPointSqr(vHatchSegment.StartPoint, ALastPoint);
    vDistance[1] := DistanceF2DPointSqr(vHatchSegment.EndPoint, ALastPoint);
    vIndexD := Integer(vDistance[0] > vDistance[1]);
    if vAccuracy > vDistance[vIndexD] then
    begin
      vAccuracy := vDistance[vIndexD];
      Result := J;
      ALastPointType := not Boolean(vIndexD);
    end;
  end;
end;

function TsgCADBoundaryData.GetNodeName: string;
begin
  Result := cnstXMLNames[xmlBoundaries].Name;
end;

procedure TsgCADBoundaryData.MakeBorderPolylines(const AConverter
  : TsgDXFConverter; const ABoundaryPolylines: TList;
  const ASolidFill: Boolean);
const
  cnstAccuracy: Double = 0.005;
var
  vHatchSegment: Tsg2DCurve;
  vAddPoint, vLastPoint: TF2DPoint;
  I, M, vIndex, Cnt, vCnt: Integer;
  vPolylineList: TF2DPointList;
  vList, vList1: Tsg2DBoundaryList;
  vLastPointType, vCurPointType: Boolean;

  procedure BoundaryLoaded;
  var
    K: Integer;
    vObj: TObject;
  begin
    M := 0;
    while M < FBoundaries.Count do
    begin
      vList := nil;
      vObj := FBoundaries[M];
      if vObj is Tsg2DBoundaryList then
        vList := FBoundaries[M]
      else
      begin
        if vObj is TList then
        begin
          vList := Tsg2DBoundaryList.Create;
          try
            FBoundaries[M] := vList;
            vList.AssignBoundary(vObj);
          finally
            vObj.Free;
          end;
        end
        else
        begin
          if vObj <> nil then
          begin
            FBoundaries[M] := nil;
            vObj.Free;
          end;
        end;
      end;
      if vList <> nil then
      begin
        K := 0;
        while K < vList.Count do
        begin
          if vList[K] <> nil then
          begin
            Tsg2DCurve(vList[K]).Loaded;
            Inc(K);
          end
          else
            vList.Delete(K);
        end;
        Inc(M);
      end;
    end;
  end;

  procedure AddF2DPointInPolyline(const APoint: TF2DPoint);
  begin
    vAddPoint := APoint;
    if (vPolylineList.Count < 1) or
      (not IsEqualF2DPoints(vPolylineList.Last, APoint)) then
      vPolylineList.Add(APoint);
  end;

  procedure CopyBackWard;
  var
    K: Integer;
  begin
    for K := vCnt downto 0 do
      AddF2DPointInPolyline(vHatchSegment.Points[K]);
  end;

  procedure CopyForWard;
  var
    K: Integer;
  begin
    for K := 0 to vCnt do
      AddF2DPointInPolyline(vHatchSegment.Points[K]);
  end;

  function GetEndOrStartPoint(ACurve: Tsg2DCurve; const AIsEnd: Boolean)
    : TF2DPoint;
  begin
    if AIsEnd then
      Result := ACurve.EndPoint
    else
      Result := ACurve.StartPoint;
  end;

  procedure CopyPoints;
  var
    J: Integer;
    vDistance: array [0 .. 1] of Extended;
  begin
    Cnt := vList.Count - 1;
    for J := 0 to Cnt do
    begin
      vHatchSegment := vList[J];
      vCnt := vHatchSegment.Count - 1;
      if vCnt > -1 then
      begin
        if J > 0 then
        begin
          vDistance[0] := DistanceF2DPointSqr(vHatchSegment.StartPoint,
            vAddPoint);
          vDistance[1] := DistanceF2DPointSqr(vHatchSegment.EndPoint,
            vAddPoint);
          if vDistance[0] < vDistance[1] then
            CopyForWard
          else
          begin
            CopyBackWard;
            vHatchSegment.Reverse(False);
            // call after CopyBackWard. Change in future versions
          end;
        end
        else
          CopyForWard;
      end;
      vHatchSegment.ClearPoints;
    end;
  end;

begin
  if ABoundaryPolylines <> nil then
    ClearList(ABoundaryPolylines);
  BoundaryLoaded;
  vAddPoint := cnstF2DPointZero;
  M := 0;
  while (M < FBoundaries.Count) and (FBoundaries[M] <> nil) do
  begin
    vList := FBoundaries[M];
    if not CanUseBoundaryList(vList, ASolidFill) then
    begin
      Inc(M);
      Continue;
    end;
    vPolylineList := TF2DPointList.Create;
    ABoundaryPolylines.Add(vPolylineList);
    vCurPointType := True;
    vLastPointType := vCurPointType;
    Cnt := vList.Count - 1;
    I := 0;
    while I < vList.Count - 1 do
    begin
      vLastPoint := GetEndOrStartPoint(vList[I], vLastPointType);
      vIndex := GetIndexOfNeighbour(vList, vLastPoint, I, cnstAccuracy,
        vLastPointType);
      if (vIndex > -1) then
      begin
        vHatchSegment := vList[I + 1];
        vList[I + 1] := vList[vIndex];
        vList[vIndex] := vHatchSegment;
      end
      else
      begin
        vLastPointType := not vCurPointType;
        repeat
          vLastPoint := GetEndOrStartPoint(vList[0], vLastPointType);
          vIndex := GetIndexOfNeighbour(vList, vLastPoint, I, cnstAccuracy,
            vLastPointType);
          if (vIndex > -1) then
          begin
            vHatchSegment := vList[vIndex];
            vList.Delete(vIndex);
            vList.Insert(0, vHatchSegment);
            Inc(I);
          end;
        until vIndex < 0;
        if I < Cnt then
        begin
          vList1 := Tsg2DBoundaryList.Create;
          FBoundaries.Insert(M + 1, vList1);
          vList1.BoundaryType := vList.BoundaryType;
          vList1.CopyFrom(vList, I + 1, Cnt - I);
          vList.Count := I + 1;
        end;
        Break;
      end;
      Inc(I);
    end;
    CopyPoints;
    Inc(M);
  end;
  // ClearBoundaryData; This is commented for AssignEntity could work
end;

function TsgCADBoundaryData.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
var
  I: Integer;
  vBoundary: TsgNode;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  if IsXMLHelp(AMode) then
    ANode.AddChildNV(cnstXMLNames[xmlBoundary].Name)
  else
    for I := 0 to FBoundaries.Count - 1 do
    begin
      vBoundary := ANode.AddChildNV(cnstXMLNames[xmlBoundary].Name);
      BoundaryToXMLNode(FBoundaries.List[I], vBoundary);
    end;
end;

{ TsgCADHatchPatternData }

function TsgCADHatchPatternData.AddPatternData(const ABasePoint: TFPoint;
  const Angle: Double; const ASign: Integer): PsgHatchPatternData;
begin
  New(Result);
  FPatterns.Add(Result);
  Result.BaseP := ABasePoint;
  Result.Offset := MakeFPoint(1, ASign * 1, 0);
  Result.LineAngle := Angle;
  Result.IsDash := False;
  Result.Lines := nil;
  Result.DashNum := 0;
end;

procedure TsgCADHatchPatternData.ApplyAngle(const AngleRel: Double);
var
  PHPD: PsgHatchPatternData;
  I: Integer;
begin
  if AngleRel = 0 then
    Exit;
  for I := FPatterns.Count - 1 downto 0 do
  begin
    PHPD := PsgHatchPatternData(FPatterns[I]);
    PHPD^.LineAngle := PHPD^.LineAngle + AngleRel;
    PHPD^.BaseP := RotateFPoint(PHPD^.BaseP, AngleRel);
    PHPD^.Offset := RotateFPoint(PHPD^.Offset, AngleRel);
  end;
end;

procedure TsgCADHatchPatternData.ApplyScale(const AScaleRel: Double);
var
  PHPD: PsgHatchPatternData;
  I, J: Integer;
begin
  if AScaleRel = 1 then
    Exit;
  for I := FPatterns.Count - 1 downto 0 do
  begin
    PHPD := PsgHatchPatternData(FPatterns[I]);
    PHPD^.BaseP.X := AScaleRel * PHPD^.BaseP.X;
    PHPD^.BaseP.Y := AScaleRel * PHPD^.BaseP.Y;
    PHPD^.BaseP.Z := 0;
    PHPD^.Offset.X := AScaleRel * PHPD^.Offset.X;
    PHPD^.Offset.Y := AScaleRel * PHPD^.Offset.Y;
    PHPD^.Offset.Z := 0;
    if PHPD^.IsDash and (PHPD^.Lines <> nil) then
      for J := PHPD^.Lines.Count - 1 downto 0 do
        PHPD^.Lines[J] := AScaleRel * PHPD^.Lines[J];
  end;
end;

procedure TsgCADHatchPatternData.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgCADHatchPatternData then
  begin
    ClearPatterns;
    CopyPatterns(TsgCADHatchPatternData(Source));
  end;
end;

procedure TsgCADHatchPatternData.ClearPatterns(const AClearCapacity: Boolean);
var
  I: Integer;
begin
  FAngle := 0;
  FName := '';
  FScale := 1;
  if FPatterns <> nil then
  begin
    for I := 0 to FPatterns.Count - 1 do
    begin
      PsgHatchPatternData(FPatterns.List[I])^.Lines.Free;
      Dispose(PsgHatchPatternData(FPatterns.List[I]));
    end;
    FPatterns.Count := 0;
  end;
end;

procedure TsgCADHatchPatternData.ClearReferences;
begin
  inherited ClearReferences;
  ClearPatterns;
end;

procedure TsgCADHatchPatternData.CopyPatterns(const APatterns
  : TsgCADHatchPatternData);
var
  I: Integer;
  vNewHPD, vOldHPD: PsgHatchPatternData;
begin
  FName := APatterns.FName;
  FAngle := APatterns.FAngle;
  FScale := APatterns.FScale;
  FPatterns.Capacity := APatterns.FPatterns.Count;
  for I := 0 to APatterns.FPatterns.Count - 1 do
  begin
    New(vNewHPD);
    FPatterns.Add(vNewHPD);
    vOldHPD := APatterns.FPatterns[I];
    vNewHPD^ := vOldHPD^;
    if vNewHPD^.Lines <> nil then
    begin
      vNewHPD^.Lines := TsgDoubleList.Create(vOldHPD^.Lines.Count);
      vNewHPD^.Lines.Assign(vOldHPD^.Lines);
    end;
  end;
end;

constructor TsgCADHatchPatternData.Create;
begin
  inherited Create;
  FAngle := 0;
  FName := '';
  FScale := 1;
  FPatterns := TList.Create;
end;

procedure TsgCADHatchPatternData.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FPatterns);
end;

function TsgCADHatchPatternData.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
var
  PHPD: PsgHatchPatternData;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlAngle:
      FAngle := ANode.ValueAsDouble;
    xmlName:
      FName := ANode.ValueAsStr;
    xmlScale:
      FScale := ANode.ValueAsDouble;
    xmlPattern:
      begin
        New(PHPD);
        FPatterns.Add(PHPD);
        FillChar(PHPD^, SizeOf(PHPD^), 0);
        HatchPatternDataFromToXMLNode(PHPD, ANode, AResult);
      end;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

function TsgCADHatchPatternData.GetNodeName: string;
begin
  Result := cnstXMLNames[xmlPatterns].Name;
end;

{ TsgCADHatchPatternData.HatchLine

  Creates the points-list for drawing a line of hatch }

procedure TsgCADHatchPatternData.HatchLine(AList: TsgDoubleList;
  Pt1, Pt2, BasePt: TFPoint; DottedSingPts: TFPointList);
var
  vDX, vDY, vCur, vLen, vPartLen, vPatternLength, vHatchLineAng, vDist1,
    vDist2: Double;
  vIndex, I, vTicksCount, vAmountPatterns: Integer;
  vPt: TFPoint;

  procedure IncIndex;
  begin
    Inc(vIndex);
    if vIndex > vTicksCount - 1 then
      vIndex := 0;
  end;

  procedure AddPt;
  var
    vPoint: TFPoint;
  begin
    vPoint.X := Pt1.X + vDX * vCur / vLen;
    vPoint.Y := Pt1.Y + vDY * vCur / vLen;
    vPoint.Z := 0.0;
    DottedSingPts.Add(vPoint);
    IncIndex;
  end;

begin
  vIndex := 0;
  vTicksCount := (AList.Count shr 1) shl 1;
  // Length of a pattern
  vPatternLength := 0.0;
  for I := 0 to (vTicksCount - 1) do
    vPatternLength := vPatternLength + Abs(AList[I]);

  vDX := Pt2.X - Pt1.X;
  vDY := Pt2.Y - Pt1.Y;
  vLen := Sqrt(Sqr(vDX) + Sqr(vDY)) { / FScale };
  if (Abs(vLen) < 0.0001) or (vPatternLength = 0) or
    ((vLen / vPatternLength) > iMaxNumDottedLines) then
  begin
    // starting point
    DottedSingPts.Add(Pt1);
    // ending point
    DottedSingPts.Add(Pt2);
    Exit;
  end;

  // Hatch line angle
  if Pt1.X <> Pt2.X then
    vHatchLineAng := ArcTan((Pt2.Y - Pt1.Y) / (Pt2.X - Pt1.X))
  else
    vHatchLineAng := Pi / 2;

  // Moving the base point under bottom boundary on distance less then length of the pattern
  if not((Abs(BasePt.Y - Pt1.Y) < fAccuracy) and
    (Abs(BasePt.Y - Pt2.Y) < fAccuracy)) then
  begin
    if Pt1.Y < Pt2.Y then
      vDist1 := Sqrt(Sqr(Pt1.X - BasePt.X) + Sqr(Pt1.Y - BasePt.Y)) { / FScale }
    else
      vDist1 := Sqrt(Sqr(Pt2.X - BasePt.X) + Sqr(Pt2.Y - BasePt.Y))
      { / FScale };
    if (BasePt.Y > Pt1.Y) or (BasePt.Y > Pt2.Y) then
    begin
      vAmountPatterns := SGFloor(vDist1 / vPatternLength) + 1;
      if Abs(vHatchLineAng - Pi / 2) > fAccuracy then
        if Tan(vHatchLineAng) >= 0 then
        begin
          BasePt.X := BasePt.X - vPatternLength * vAmountPatterns *
            Cos(vHatchLineAng);
          BasePt.Y := BasePt.Y - vPatternLength * vAmountPatterns *
            Sin(vHatchLineAng);
        end
        else
        begin
          BasePt.X := BasePt.X + vPatternLength * vAmountPatterns *
            Cos(vHatchLineAng);
          BasePt.Y := BasePt.Y + vPatternLength * vAmountPatterns *
            Sin(vHatchLineAng);
        end
      else
        BasePt.Y := BasePt.Y - vPatternLength * vAmountPatterns;
    end
    else
    begin
      vAmountPatterns := SGFloor(vDist1 / vPatternLength);
      if Abs(vHatchLineAng - Pi / 2) > fAccuracy then
        if Tan(vHatchLineAng) >= 0 then
        begin
          BasePt.X := BasePt.X + vPatternLength * vAmountPatterns *
            Cos(vHatchLineAng);
          BasePt.Y := BasePt.Y + vPatternLength * vAmountPatterns *
            Sin(vHatchLineAng);
        end
        else
        begin
          BasePt.X := BasePt.X - vPatternLength * vAmountPatterns *
            Cos(vHatchLineAng);
          BasePt.Y := BasePt.Y - vPatternLength * vAmountPatterns *
            Sin(vHatchLineAng);
        end
      else
        BasePt.Y := BasePt.Y + vPatternLength * vAmountPatterns;
    end;
  end
  else
  begin
    if Pt1.X < Pt2.X then
      vDist1 := Sqrt(Sqr(Pt1.X - BasePt.X) + Sqr(Pt1.Y - BasePt.Y)) { / FScale }
    else
      vDist1 := Sqrt(Sqr(Pt2.X - BasePt.X) + Sqr(Pt2.Y - BasePt.Y))
      { / FScale };
    if (BasePt.X > Pt1.X) or (BasePt.Y > Pt2.Y) then
    begin
      vAmountPatterns := SGFloor(vDist1 / vPatternLength) + 1;
      BasePt.X := BasePt.X - vPatternLength * vAmountPatterns;
    end
    else
    begin
      vAmountPatterns := SGFloor(vDist1 / vPatternLength);
      BasePt.X := BasePt.X + vPatternLength * vAmountPatterns;
    end;
  end;

  vDist1 := Sqrt(Sqr(Pt1.X - BasePt.X) + Sqr(Pt1.Y - BasePt.Y)) { / FScale };
  vDist2 := Sqrt(Sqr(Pt2.X - BasePt.X) + Sqr(Pt2.Y - BasePt.Y)) { / FScale };
  if vDist1 > vDist2 then
  begin
    vDist1 := vDist2;
    vPt := Pt1;
    Pt1 := Pt2;
    Pt2 := vPt;
    vDX := Pt2.X - Pt1.X;
    vDY := Pt2.Y - Pt1.Y;
  end;

  vCur := 0.0;
  // this accuracy is connected with the accuracy of the function sgLines.CompareValues
  if not IsEqual(vPatternLength, vDist1, fExtendedResolution) then
  begin
    I := -1;
    vPartLen := 0.0;
    repeat
      Inc(I);
      if I > vTicksCount - 1 then
      begin
        Exit;
      end;
      vPartLen := vPartLen + Abs(AList[I]);
    until vPartLen >= vDist1;
    if AList[I] >= 0 then
      AddPt;
    vCur := vPartLen - vDist1;
    if vCur >= vLen then
    begin
      vCur := vLen;
      if AList[I] >= 0 then
        AddPt;
      Exit;
    end;
    if not((I <> vTicksCount - 1) and (AList[I] * AList[I + 1] > 0) or
      (I = vTicksCount - 1) and (AList[I] * AList[0] > 0)) then
      AddPt;
    Inc(I);
    while I <= vTicksCount - 1 do
    begin
      vCur := vCur + Abs(AList[I]);
      if vCur >= vLen then
      begin
        vCur := vLen;
        if AList[I] >= 0 then
          AddPt;
        Exit;
      end;
      if not((I <> vTicksCount - 1) and (AList[I] * AList[I + 1] > 0) or
        (I = vTicksCount - 1) and (AList[I] * AList[0] > 0)) then
        AddPt;
      Inc(I);
    end;
  end
  else if AList[0] >= 0 then
    AddPt;
  vIndex := 0;
  while True do
  begin
    vCur := vCur + Abs(AList[vIndex]);
    if (Abs(vCur - vLen) < fAccuracy) or (vCur > vLen) then
    begin
      vCur := vLen;
      if AList[vIndex] >= 0 then
        AddPt;
      Exit;
    end;
    if not((vIndex <> vTicksCount - 1) and (AList[vIndex] * AList[vIndex + 1] >
      0) or (vIndex = vTicksCount - 1) and (AList[vIndex] * AList[0] > 0)) then
      AddPt
    else
      IncIndex;
  end;
end;

procedure TsgCADHatchPatternData.NewLineWithBasePAndAddList(AList: TList;
  APoint1, APoint2, ABasePoint: TF2DPoint);
var
  PLineWBP: PLineWithBaseP;
begin
  New(PLineWBP);
  PLineWBP^.P1.X := APoint1.X;
  PLineWBP^.P1.Y := APoint1.Y;
  PLineWBP^.P2.X := APoint2.X;
  PLineWBP^.P2.Y := APoint2.Y;
  PLineWBP^.BP.X := ABasePoint.X;
  PLineWBP^.BP.Y := ABasePoint.Y;
  AList.Add(PLineWBP);
end;

function TsgCADHatchPatternData.ParseLines(const AParsedLines: TFPointList;
  const ABoundaryPolylines: TList; const ABox: TFRect;
  const AHatchStyle: TsgHatchStyle): TsgHatchStyle;
var
  I, K, M: Integer;
  vPoly { , vBoundaries } : TList;
  vGlobP1, vGlobP2: TFPoint;
  vNewBaseP: TFPoint;
  vCurPattern: TsgHatchPatternData;
  xPoly: TFPointList;
  wPoly, { vTempPoly, } wTempPoly: TList;
  U, V, vCyclesCount: Integer;
  P, P1, vBaseP: TFPoint;
  vFlip: Boolean;
  vMemoryUses: Integer;
  vTickCountStart: Cardinal;

  procedure CheckMemorySize(ASize: Integer);
  begin
    Inc(vMemoryUses, ASize);
    if vMemoryUses > cnstLimitByHatch then
      raise EsgLimitMemoryUsesException.Create(sHatchMemoryLimit);
  end;

  procedure SetPoly;
  begin
    NewLineWithBasePAndAddList(vPoly, MakeF2DPointFrom3D(vGlobP1),
      MakeF2DPointFrom3D(vGlobP2), MakeF2DPointFrom3D(vNewBaseP));
    CheckMemorySize(SizeOf(TLineWithBaseP) + SizeOf(Pointer));
  end;

  procedure GetGlobP(ABaseP: TFPoint; APttOffset: TFPoint; AAng: Double;
    ALine: TsgDoubleList);
  var
    vD, vNewD, vCross, CalcBaseP1, CalcBaseP2: TFPoint;
    vLeftStopPoint, vRightStopPoint: PFPoint;
    vLeftXBorder, vRightXBorder, vPatternLength, TanAAng, B: Double;
    vStepCount: Extended; // this is UInt64 (value returned by function Trunc)
    Sn, Cs: Extended;

    procedure SwapDoubles(var A1, A2: Double);
    var
      C: Double;
    begin
      C := A1;
      A1 := A2;
      A2 := C;
    end;

    function Len(const P1, P2: TFPoint): Double;
    begin
      Result := Sqrt(Sqr(P1.X - P2.X) + Sqr(P1.Y - P2.Y));
    end;

    function GetPatternLength: Double;
    var
      J: Integer;
    begin
      Result := 0;
      if ALine <> nil then
        for J := 0 to ALine.Count - 1 do
          Result := Result + Abs(ALine[J]);
    end;

    procedure SetBase(I: Integer);
    var
      D: Double;
    begin
      D := vD.V[I];
      if (vCross.V[I] - ABaseP.V[I]) * D <= 0 then
        D := -D;
      ABaseP.V[I] := ABaseP.V[I] + D * vStepCount;
    end;

    procedure SetCalcBase(coef: Double);
    begin
      coef := coef * vPatternLength;
      CalcBaseP1.X := ABaseP.X + Cs * coef;
      CalcBaseP1.Y := ABaseP.Y + Sn * coef;
      CalcBaseP2.X := ABaseP.X - Cs * coef;
      CalcBaseP2.Y := ABaseP.Y - Sn * coef;
    end;

    function SetBorders(Cond: Boolean): Integer;
    begin
      Result := Ord(Cond) - Ord(not Cond);
      vLeftXBorder := ABox.Right;
      vRightXBorder := ABox.Left;
      vLeftStopPoint := @vGlobP1;
      vRightStopPoint := @vGlobP2;
      if Cond then
      begin
        SwapDoubles(vLeftXBorder, vRightXBorder);
        SwapPointers(Pointer(vLeftStopPoint), Pointer(vRightStopPoint));
      end;
      vNewBaseP := ABaseP;
    end;

    procedure Ortho(IX: Integer; const AMin, AMax: TFPoint);
    var
      IY, N: Integer;
      vMin, vMax, vKoef: Double;
    begin
      IY := IX xor 1;
      if Abs(vD.V[IX]) > fAccuracy then
      begin
        vNewD := MakeFPoint(Abs(vD.X), Abs(vD.Y), 0);
        vMin := Min(AMin.V[IX], AMax.V[IX]);
        vMax := Max(AMin.V[IX], AMax.V[IX]);
        N := Ceil((vMax - ABaseP.V[IX]) / (vNewD.V[IX] * 2)) shl 1;
        vKoef := 1 - Integer((vD.X * vD.Y) < 0) shl 1;
        vNewBaseP.V[IX] := ABaseP.V[IX] + (N - 1 * IX) * vNewD.V[IX];
        vNewBaseP.V[IY] := ABaseP.V[IY] + (N - 1 * IX) * vNewD.V[IY] * vKoef;
        while vNewBaseP.V[IX] >= vMin do
        begin
          vGlobP1.V[IX] := vNewBaseP.V[IX];
          vGlobP1.V[IY] := AMax.V[IY];
          vGlobP2.V[IX] := vNewBaseP.V[IX];
          vGlobP2.V[IY] := AMin.V[IY];
          SetPoly;
          vNewBaseP.V[IX] := vNewBaseP.V[IX] - vNewD.V[IX];
          vNewBaseP.V[IY] := vNewBaseP.V[IY] - vNewD.V[IY] * vKoef;
        end;
      end;
    end;

    procedure Diagonal(ASign: Integer; ABottom, ATop: Double);
      procedure SetGlob;
      begin
        vGlobP1.Y := ABottom;
        vGlobP1.X := vNewBaseP.X + (ABottom - vNewBaseP.Y) / TanAAng;
        vGlobP2.Y := ATop;
        vGlobP2.X := vNewBaseP.X + (ATop - vNewBaseP.Y) / TanAAng;
      end;

    begin
      while True do // into right direction from base point
      begin
        SetGlob;
        if ASign * (vRightXBorder - vRightStopPoint^.X) <= 0.0 then
          Break;
        SetPoly;
        vNewBaseP.X := vNewBaseP.X + vD.X;
        vNewBaseP.Y := vNewBaseP.Y + vD.Y;
      end;
      vNewBaseP := ABaseP;
      vNewBaseP.X := vNewBaseP.X - vD.X;
      vNewBaseP.Y := vNewBaseP.Y - vD.Y;
      while True do // into left direction from base point
      begin
        SetGlob;
        if ASign * (vLeftStopPoint^.X - vLeftXBorder) <= 0.0 then
          Break;
        SetPoly;
        vNewBaseP.X := vNewBaseP.X - vD.X;
        vNewBaseP.Y := vNewBaseP.Y - vD.Y;
      end;
    end;

  begin
    if (ABox.Top = ABox.Bottom) or (ABox.Left = ABox.Right) then
      Exit;
    vD := APttOffset;
    TanAAng := Tan(AAng);
    if vD.X <> 0 then
    begin
      if not(Abs(Pi / 2 - AAng) < fAccuracy) then
        if Abs(vD.Y / vD.X - TanAAng) < 0.00001 then
          Exit; // raise EsgDXFHatchError.Create('Hatch parameters error');
    end
    else if (Abs(Pi / 2 - AAng) < fAccuracy) or (vD.Y = 0) then
      Exit; // raise EsgDXFHatchError.Create('Hatch parameters error');

    SinCos(AAng, Sn, Cs);
    // Moving base point by OFFSET
    if not(Abs(Pi / 2 - AAng) < fAccuracy) then
    begin
      B := ABox.Top - TanAAng * ABox.Left;
      if vD.X = 0 then
        vCross.X := ABox.Left
      else
        vCross.X := (ABaseP.Y - ABaseP.X * vD.Y / vD.X - B) /
          (TanAAng - vD.Y / vD.X);
      vCross.Y := TanAAng * vCross.X + B;
    end
    else
    begin
      vCross.X := ABox.Left;
      vCross.Y := vD.Y * vCross.X / vD.X + ABaseP.Y - ABaseP.X * vD.Y / vD.X;
    end;
    vStepCount := Trunc(Len(vCross, ABaseP) / Len(vD, cnstFPointZero));
    SetBase(0);
    SetBase(1);

    // Length of a pattern
    vPatternLength := GetPatternLength;
    // Moving base point by PATTERN
    if vPatternLength <> 0.0 then
    begin
      vStepCount := Trunc(Len(ABox.TopLeft, vCross) / vPatternLength);
      SetCalcBase(vStepCount);
    end
    else
    begin
      vPatternLength := Len(vCross, ABaseP);
      SetCalcBase(1.0);
    end;
    if Len(ABox.TopLeft, CalcBaseP1) < Len(ABox.TopLeft, CalcBaseP2) then
      ABaseP := CalcBaseP1
    else
      ABaseP := CalcBaseP2;

    // By hatch line angle
    if Abs(Cs) < 0.001 then // vertical
    begin
      if Result = hsHorizontal then
        Result := hsCross
      else
        Result := hsVertical;
      Ortho(0, ABox.TopLeft, ABox.BottomRight);
    end
    else if Abs(Sn) < 0.001 then // horisontal
    begin
      if Result = hsVertical then
        Result := hsCross
      else
        Result := hsHorizontal;
      Ortho(1, ABox.BottomRight, ABox.TopLeft);
    end
    else if ((Cs > 0) and (Sn > 0)) or ((Cs < 0) and (Sn < 0)) then
    // 1, 3 quadrants
    begin
      if Result = hsBDiagonal then
        Result := hsDiagCross
      else
        Result := hsFDiagonal;
      Diagonal(SetBorders(vD.Y < vD.X * TanAAng), ABox.Bottom, ABox.Top);
    end
    else // 2, 4 quadrants
    begin
      if Result = hsFDiagonal then
        Result := hsDiagCross
      else
        Result := hsBDiagonal;
      Diagonal(SetBorders(vD.Y > vD.X * TanAAng), ABox.Top, ABox.Bottom);
    end;
  end;

  procedure CheckTime(const AStartTime: Cardinal);
  begin
    if (GetTickCount - AStartTime) > cnstLimitTimeByHatch then
      raise EsgLimitTimeUsesException.Create(sHatchTimeLimit);
  end;

begin
  Result := AHatchStyle;
  AParsedLines.Clear(False);
  vMemoryUses := 0;
  vTickCountStart := GetTickCount;
  vPoly := TList.Create;
  xPoly := TFPointList.Create;
  wPoly := TList.Create;
  wTempPoly := TList.Create;
  try
    for K := 0 to FPatterns.Count - 1 do
    begin
      vFlip := False;
      vCurPattern := PsgHatchPatternData(FPatterns.Items[K])^;
      try
        ClearRecordList(vPoly, False);
        ClearRecordList(wPoly, False);
        GetGlobP(vCurPattern.BaseP, vCurPattern.Offset,
          Radian(vCurPattern.LineAngle), vCurPattern.Lines);
        for U := 0 to vPoly.Count - 1 do
        begin
          ParseLinesHatch(ABoundaryPolylines, vPoly.Items[U], wTempPoly);
          CheckTime(vTickCountStart);
          CheckMemorySize((SizeOf(Pointer) + SizeOf(TLineWithBaseP) *
            wTempPoly.Count));
          V := 0;
          while V <= wTempPoly.Count - 2 do
          begin
            NewLineWithBasePAndAddList(wPoly, TF2DPoint(wTempPoly.Items[V]^),
              TF2DPoint(wTempPoly.Items[V + 1]^),
              TLineWithBaseP(vPoly.Items[U]^).BP);
            Inc(V, 2);
          end;
          ClearRecordList(wTempPoly, False);
        end;

        if vCurPattern.IsDash then
        begin
          if wPoly.Count = 0 then
            Continue;
          vCyclesCount := SGFloor(vCurPattern.LineAngle / 360);
          vFlip := vCurPattern.LineAngle - vCyclesCount * 360 >= 180;
          if vFlip then // Rotate the pattern
            vCurPattern.Lines.Flip;

          P.Z := 0;
          P1.Z := 0;
          vBaseP.Z := 0;
          for M := 0 to wPoly.Count - 1 do
          begin
            xPoly.Clear(False);
            P.X := TLineWithBaseP(wPoly.Items[M]^).P1.X;
            P.Y := TLineWithBaseP(wPoly.Items[M]^).P1.Y;

            P1.X := TLineWithBaseP(wPoly.Items[M]^).P2.X;
            P1.Y := TLineWithBaseP(wPoly.Items[M]^).P2.Y;

            vBaseP.X := TLineWithBaseP(wPoly.Items[M]^).BP.X;
            vBaseP.Y := TLineWithBaseP(wPoly.Items[M]^).BP.Y;
            if not(vCurPattern.Lines.Count <= 1) then
            begin
              HatchLine(vCurPattern.Lines, P, P1, vBaseP, xPoly);
              CheckTime(vTickCountStart);
              CheckMemorySize(SizeOf(TFPoint) * xPoly.Count);
              for I := 0 to xPoly.Count - 1 do
                AParsedLines.Add(xPoly[I]);
            end
            else
            begin
              AParsedLines.Add(P);
              AParsedLines.Add(P1);
            end;
          end;
        end
        else
        begin
          for M := 0 to wPoly.Count - 1 do
          begin
            AParsedLines.Add(MakeFPoint(TLineWithBaseP(wPoly.Items[M]^).P1.X,
              TLineWithBaseP(wPoly.Items[M]^).P1.Y));
            AParsedLines.Add(MakeFPoint(TLineWithBaseP(wPoly.Items[M]^).P2.X,
              TLineWithBaseP(wPoly.Items[M]^).P2.Y));
          end;
        end;
      finally
        if AParsedLines.Count > cnstLimitByHatch div SizeOf(TFPoint) then
          raise EsgLimitMemoryUsesException.Create(sHatchMemoryLimit);
        if vFlip then
          vCurPattern.Lines.Flip;
      end;
    end;
  finally
    ClearRecordList(vPoly);
    ClearRecordList(wPoly);
    ClearRecordList(wTempPoly);
    vPoly.Free;
    xPoly.Free;
    wPoly.Free;
    wTempPoly.Free;
  end;
end;

procedure TsgCADHatchPatternData.DoAngle(const AValue: Double);
var
  vAngle, vValue: Double;
begin
  if sgModAngle(AValue, vValue) then
  begin
    vAngle := (vValue - FAngle);
    ApplyAngle(vAngle);
    FAngle := vValue;
  end;
end;

procedure TsgCADHatchPatternData.DoScale(const AValue: Double);
var
  vScale: Double;
begin
  if FScale > fAccuracy then
    vScale := AValue / FScale
  else
    vScale := AValue;
  ApplyScale(vScale);
  FScale := AValue;
end;

function TsgCADHatchPatternData.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
var
  I: Integer;
  vPattern: TsgNode;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlName].Name).ValueAsStr := FName;
  ANode.AddAttribNV(cnstXMLNames[xmlAngle].Name).ValueAsDouble := FAngle;
  ANode.AddAttribNV(cnstXMLNames[xmlScale].Name).ValueAsDouble := FScale;
  if IsXMLHelp(AMode) then
    ANode.AddChildNV(cnstXMLNames[xmlPattern].Name)
  else
    for I := 0 to FPatterns.Count - 1 do
    begin
      vPattern := ANode.AddChildNV(cnstXMLNames[xmlPattern].Name);
      HatchPatternDataToXMLNode(FPatterns.List[I], vPattern);
    end;
end;

function TsgCADHatchPatternData.HatchPatternDataFromToXMLNode
  (const AData: PsgHatchPatternData; const ANode: TsgNodeSample;
  const AResult: IsgResultNode = nil): Integer;
var
  I: Integer;
  vAttrib, vLines, vLinesCount, vDash: TsgNodeSample;
  vID: TsgXMLId;
begin
  Result := cnstXML_OK;
  for I := 0 to ANode.AttributeNodesCount - 1 do
  begin
    vAttrib := ANode.AttributeNodes[I];
    vID := GetXMLId(vAttrib.Name);
    case vID of
      xmlLineAngle:
        AData.LineAngle := vAttrib.ValueAsDouble;
      xmlBasePoint:
        AData.BaseP := vAttrib.ValueAsFPoint;
      xmlOffset:
        AData.Offset := vAttrib.ValueAsFPoint;
      xmlIsSolid:
        AData.IsDash := vAttrib.ValueAsBool;
      xmlCount:
        AData.DashNum := vAttrib.ValueAsInt;
    end;
  end;
  vLines := ANode.GetChildByName(cnstXMLNames[xmlLines].Name);
  if Assigned(vLines) then
  begin
    AData.Lines := TsgDoubleList.Create;
    vLinesCount := ANode.GetAttributeByName(cnstXMLNames[xmlCount].Name);
    if Assigned(vLinesCount) then
      AData.Lines.Capacity := vLinesCount.ValueAsInt;
    for I := 0 to vLines.ChildNodesCount - 1 do
    begin
      vDash := vLines.ChildNodes[I];
      if (vDash.AttributeNodesCount > 0) and
        SameText(vDash.Name, cnstXMLNames[xmlDash].Name) then
        AData.Lines.Add(vDash.AttributeNodes[0].ValueAsDouble);
    end;
  end;
end;

function TsgCADHatchPatternData.HatchPatternDataToXMLNode
  (const AData: PsgHatchPatternData; const ANode: TsgNode): Integer;
var
  I: Integer;
  vNode: TsgNode;
begin
  Result := cnstXML_OK;
  ANode.AddAttribNV(cnstXMLNames[xmlLineAngle].Name).ValueAsDouble :=
    AData.LineAngle;
  ANode.AddAttribNV(cnstXMLNames[xmlBasePoint].Name).ValueAsFPoint :=
    AData.BaseP;
  ANode.AddAttribNV(cnstXMLNames[xmlOffset].Name).ValueAsFPoint := AData.Offset;
  ANode.AddAttribNV(cnstXMLNames[xmlIsSolid].Name).ValueAsBool := AData.IsDash;
  ANode.AddAttribNV(cnstXMLNames[xmlCount].Name).ValueAsInt := AData.DashNum;
  if Assigned(AData.Lines) and (AData.Lines.Count > 0) then
  begin
    vNode := ANode.AddChildNV(cnstXMLNames[xmlLines].Name);
    vNode.AddAttribNV(cnstXMLNames[xmlCount].Name).ValueAsInt :=
      AData.Lines.Count;
    for I := 0 to AData.Lines.Count - 1 do
      vNode.AddChildNV(cnstXMLNames[xmlDash].Name).AddAttribNV(cnstXMLValue)
        .ValueAsDouble := AData.Lines[I];
  end;
end;

{ TsgDXFSectionEntities }

constructor TsgDXFSectionEntities.CreateByConverter(const AConverter
  : TsgDXFConverter);
begin
  inherited CreateByConverter(AConverter);
  Name := cnstXMLNames[xmlEntities].Name;
end;

function TsgDXFSectionEntities.FromXML(const ANode: TsgNodeSample;
  const AResult: IsgResultNode = nil): Integer;
begin
  // No call inherited
  if (Converter <> nil) and (ANode.ChildNodesCount = 1) then
    Result := GetEntities.FromXML(ANode.ChildNodes[0], AResult)
  else
    Result := cnstXML_ERROR;
end;

function TsgDXFSectionEntities.GetEntities: TsgDXFEntity;
begin
  Result := Converter.Sections[csEntities];
end;

function TsgDXFSectionEntities.ToXML(const AParrentNode: TsgNode;
  const AMode: TsgXMLModes): TsgNode;
begin
  Result := inherited ToXML(AParrentNode, AMode);
  if Converter <> nil then
    GetEntities.ToXML(Result, AMode);
end;

{ TsgMapEntities }

procedure TsgMapEntities.ActivateRegister;
var
  I: Integer;
  vSection: TsgDXFGroup;

  procedure AddEntities(const AEntity: TsgDXFEntity);
  var
    J: Integer;
  begin
    if UseEntity(AEntity) then
      FEntities.Add(AEntity);
    if FEntities.Capacity < (FEntities.Count + AEntity.Count) then
      FEntities.Capacity := FEntities.Capacity + AEntity.Count;
    for J := 0 to AEntity.Count - 1 do
      AddEntities(AEntity[J]);
  end;

begin
  if not FEntities.Sorted then
  begin
    FEntities.Count := 0;
    FEntities.Duplicates := dupAccept;
    for I := Low(cnstSectionsByFindObject) to High(cnstSectionsByFindObject) do
    begin
      vSection := FConverter.Sections[cnstSectionsByFindObject[I]];
      if not Assigned(vSection) then
        Continue;
      AddEntities(vSection);
    end;
    FEntities.Sorted := True;
    FEntities.Duplicates := dupIgnore;
  end;
end;

procedure TsgMapEntities.AddEntitiesToGeneratedList(const AEntities
  : TsgDXFEntity);
var
  I: Integer;
  vChildEntity: TsgDXFEntity;
begin
  FEntitiesWithGeneratedHandles.Sorted := False;
  try
    for I := 0 to AEntities.Count - 1 do
    begin
      vChildEntity := AEntities.Entities[I];
      if vChildEntity.CanHaveHandle then
      begin
        vChildEntity.SetConverter(FConverter);
        FEntitiesWithGeneratedHandles.Add(vChildEntity);
      end;
    end;
  finally
    FEntitiesWithGeneratedHandles.Sorted := True;
  end;
end;

procedure TsgMapEntities.AddEntityToGeneratedList(const AEntity: TsgDXFEntity);
begin
  FEntitiesWithGeneratedHandles.Add(AEntity);
end;

constructor TsgMapEntities.Create(const AConverter: TsgDXFConverter);
begin
  inherited Create;
  FConverter := AConverter;
  FEntities := TsgList.Create;
  FEntities.Capacity := cnstGeneratedHandlesCapacity;
  FEntities.ProcCompare := FConverter.CompareEntities;
  FEntities.Duplicates := dupAccept;
  FEntities.Sorted := False;
  FFindEntity := TsgDXFObjectEntity.Create;
end;

procedure TsgMapEntities.CreateGeneratedList;
begin
  if not Assigned(FEntitiesWithGeneratedHandles) then
  begin
    FEntitiesWithGeneratedHandles := TsgList.Create;
    FEntitiesWithGeneratedHandles.Sorted := True;
    FEntitiesWithGeneratedHandles.Duplicates := dupIgnore;
    FEntitiesWithGeneratedHandles.Capacity := cnstGeneratedHandlesCapacity;
  end;
end;

destructor TsgMapEntities.Destroy;
begin
  FreeAndNil(FEntitiesWithGeneratedHandles);
  FreeAndNil(FFindEntity);
  FreeAndNil(FEntities);
  inherited Destroy;
end;

function TsgMapEntities.GetEntityByHandle(const AHandle: UInt64): TsgDXFEntity;
var
  I, vIndex: Integer;
  vEntity: TsgDXFEntity;
  vSection: TsgDXFGroup;
begin
  Result := nil;
  if AHandle <> cnstBadHandle then
  begin
    if FEntities.Sorted then
    begin
      FFindEntity.FHandle := AHandle;
      vIndex := FEntities.IndexOf(FFindEntity);
      if vIndex > -1 then
        Result := FEntities[vIndex];
    end;
    if Result = nil then
    begin
      for I := Low(cnstSectionsByFindObject)
        to High(cnstSectionsByFindObject) do
      begin
        vSection := FConverter.Sections[cnstSectionsByFindObject[I]];
        if not Assigned(vSection) then
          Continue;
        vEntity := vSection.FindEntByHandle(AHandle, cnstSectionsByFindObject[I]
          <> csLayouts);
        if Assigned(vEntity) then
        begin
          Result := vEntity;
          Break;
        end;
      end;
    end;
  end;
end;

function TsgMapEntities.HasGeneratedList: Boolean;
begin
  Result := Assigned(FEntitiesWithGeneratedHandles);
end;

procedure TsgMapEntities.RegEntity(const AEntity: TsgDXFEntity);
var
  vIndex: Integer;
begin
  if UseEntity(AEntity) then
  begin
    if FEntities.Sorted then
    begin
      vIndex := FEntities.IndexOf(AEntity);
      if vIndex > -1 then
      begin
        if FEntities[vIndex] <> AEntity then
          raise Exception.Create('RegisterEntity: $' +
            IntToHex(AEntity.Handle, 0));
      end
      else
        FEntities.Add(AEntity);
    end
    else
      FEntities.Add(AEntity);
  end;
end;

procedure TsgMapEntities.UnActivateRegister;
begin
  FEntities.Sorted := False;
end;

procedure TsgMapEntities.UnRegEntity(const AEntity: TsgDXFEntity);
var
  vIndex: Integer;
begin
  if UseEntity(AEntity) and FEntities.Sorted then
  begin
    vIndex := FEntities.IndexOf(AEntity);
    if vIndex > -1 then
    begin
      if FEntities[vIndex] = AEntity then
        FEntities.Delete(vIndex)
      else
        raise Exception.Create('UnRegisterEntity: $' +
          IntToHex(AEntity.Handle, 0));
    end
    else
      UnActivateRegister;
  end;
end;

function TsgMapEntities.UseEntity(const AEntity: TsgDXFEntity): Boolean;
begin
  Result := AEntity.CanHaveHandle and (AEntity.Handle <> cnstBadHandle);
end;

function TsgMapEntities.RemoveEntityFromGeneratedList(const AEntity
  : TsgDXFEntity): Boolean;
var
  vIndex: Integer;
begin
  Result := False;
  vIndex := FEntitiesWithGeneratedHandles.Remove(AEntity);
  if vIndex > -1 then
    Result := True;
end;

procedure TsgMapEntities.ApplyAndFreeGeneratedList;
var
  J: Integer;
  vEntity: TsgDXFEntity;
begin
  if Assigned(FEntitiesWithGeneratedHandles) then
  begin
    try
      for J := 0 to FEntitiesWithGeneratedHandles.Count - 1 do
      begin
        vEntity := TsgDXFEntity(FEntitiesWithGeneratedHandles[J]);
        if vEntity.Handle = cnstBadHandle then
        begin
          Inc(FConverter.FMaxHandle);
          vEntity.Handle := FConverter.FMaxHandle;
        end;
      end;
    finally
      FreeAndNil(FEntitiesWithGeneratedHandles);
    end;
  end;
end;

{ TListNotifyClearWrapper }

procedure TListNotifyClearWrapper.Clear;
begin
  FListNotify.Clear;
end;

procedure TListNotifyClearWrapper.ClearListNotify(Ptr: Pointer;
  Action: TListNotification);
begin
  DoNotify(Ptr, Action);
  case Action of
    lnDeleted, lnExtracted:
      TObject(Ptr).Free
  end;
end;

constructor TListNotifyClearWrapper.Create(const AListNotify: TListNotify;
  const ADoFree: Boolean);
begin
  FListNotify := AListNotify;
  FDoFree := ADoFree;
  if FDoFree then
  begin
    FNotify := AListNotify.OnNotify;
    AListNotify.OnNotify := ClearListNotify;
  end;
end;

destructor TListNotifyClearWrapper.Destroy;
begin
  if FDoFree then
    FListNotify.OnNotify := FNotify;
  inherited Destroy;
end;

procedure TListNotifyClearWrapper.DoNotify(Ptr: Pointer;
  Action: TListNotification);
begin
  if Assigned(FNotify) then
    FNotify(Ptr, Action);
end;

{ TListNotifyClearWrapperGroup }

procedure TListNotifyClearWrapperGroup.ClearListNotify(Ptr: Pointer;
  Action: TListNotification);
var
  Ent: TsgDXFEntity absolute Ptr;
  Item: TsgOwneredItem;
begin
  DoNotify(Ptr, Action);
  case Action of
    lnExtracted, lnDeleted:
      begin
        Item := TsgOwneredItem(Ent.GetNamedItem);
        if Assigned(Item) and (Item.RefCount = 0) then
          TObject(Ptr).Destroy;
      end;
  end;
end;

{ TsgTableItem }

{$IFDEF SG_CALC_INSTANCE_SIZES}

procedure TsgTableItem.FreeInstance;
begin
  Dec(TsgDXFEntity.TotalAllocated, InstanceSize);
  inherited FreeInstance;
end;

class function TsgTableItem.NewInstance: TObject;
begin
  Result := inherited NewInstance;
  Inc(TsgDXFEntity.TotalAllocated, InstanceSize);
end;
{$ENDIF}

function TsgTableItem.GetItemObject(const AValue: TsgDXFEntity): TsgOwneredItem;
begin
  if Assigned(AValue) and (AValue.ClassType <> TsgLinkObject) then
    Result := TsgOwneredItem(AValue.GetNamedItem)
  else
    Result := nil;
end;

function TsgTableItem.IsValidItem: Boolean;
begin
  Result := GetItemObject(FItem) <> nil;
end;

procedure TsgTableItem.SetItem(const Value: TsgDXFEntity);
var
  Item: TsgOwneredItem;
begin
  if FItem <> Value then
  begin
    Item := GetItemObject(FItem);
    if Assigned(Item) and (Item.ObjRelease = 0) and (Item.Owner = nil) then
      FItem.Destroy;
    FItem := Value;
    if IsValidItem then
      GetItemObject(FItem).ObjAddRef;
  end;
end;

{ TsgStyleItem }

procedure TsgStyleItem.SetItem(const Value: TsgDXFEntity);
begin
  if FItem <> Value then
  begin
    if IsValidItem then
      if (GetItemObject(FItem).ObjRelease = 0) and
        (GetItemObject(FItem).Owner = nil) then
        FItem.Destroy;
    FItem := Value;
    if Assigned(FNotifyChange) then
      FNotifyChange(Self);
    if IsValidItem then
      GetItemObject(FItem).ObjAddRef;
  end;
end;

{ TsgOwnwredItem }

constructor TsgOwneredItem.Create(AAncestor: TsgDXFEntity);
begin
  inherited Create;
end;

{$IFDEF SG_CALC_INSTANCE_SIZES}

procedure TsgOwneredItem.FreeInstance;
begin
  Dec(TsgDXFEntity.TotalAllocated, InstanceSize);
  inherited FreeInstance;
end;

class function TsgOwneredItem.NewInstance: TObject;
begin
  Result := inherited NewInstance;
  Inc(TsgDXFEntity.TotalAllocated, InstanceSize);
end;
{$ENDIF}

function TsgOwneredItem.GetAncestor: TsgDXFEntity;
begin
  Result := nil;
end;

function TsgOwneredItem.ObjAddRef: Integer;
begin
  Inc(FRefCount);
  Result := FRefCount;
end;

function TsgOwneredItem.ObjRelease: Integer;
begin
  Dec(FRefCount);
  Result := FRefCount;
end;

procedure TsgOwneredItem.SetOwner(const AOwner: TsgDXFEntity);
begin
  if FOwner <> AOwner then
  begin
    if FOwner = nil then
      ObjAddRef;
    FOwner := AOwner;
    if FOwner = nil then
      ObjRelease;
  end;
end;

{ TsgNamedItem }

constructor TsgNamedItem.Create(AAncestor: TsgDXFEntity);
begin
  inherited Create(AAncestor);
  FAncestor := AAncestor;
end;

function TsgNamedItem.GetAncestor: TsgDXFEntity;
begin
  Result := FAncestor;
end;

procedure TsgNamedItem.SetName(const AName: string);
begin
  if FName <> AName then
  begin
    if Assigned(FOwner) then
      FOwner.DeleteItem(FAncestor);
    FName := AName;
    if Assigned(FOwner) then
      FOwner.AddItem(FAncestor);
  end;
end;

{ TsgDWGPolyline }

constructor TsgDWGPolyline.Create;
begin
  inherited Create;
end;

{$IFDEF SG_BREP_TOPOLOGY}
{ TsgBrepObjectTopology }

function TsgBrepObjectTopology.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlOriginalNameOCC].Name).ValueAsStr :=
    FOriginalName;
  if IsFullPropsOrXMLHelp(AMode) or (FVolume > 0) then
    ANode.AddAttribNV(cnstXMLNames[xmlVolumeOCC].Name).ValueAsDouble := FVolume;
  ANode.AddAttribNV(cnstXMLNames[xmlAreaOCC].Name).ValueAsDouble := FArea;
  ANode.AddAttribNV(cnstXMLNames[xmlCenterMassOCC].Name).ValueAsFPoint :=
    FCenterMass;
end;

{$ENDIF}
{ TsgDXFConverterExtented }

constructor TsgConverterExtented.Create(const AOwner: TsgDXFConverter);
begin
  inherited Create;
  FOwner := AOwner;
  FHandleArray := TsgInt64List.Create;
  FHandleArray.Count := cnstMaxSaveHandleXML;
  FSelectedHandles := TsgInt64List.Create;
  if not Assigned(FOwner) then
    raise Exception.Create('Does not have owner!');
end;

destructor TsgConverterExtented.Destroy;
begin
  FOwner := nil;
  FHandleArray.Free;
  FSelectedHandles.Free;
  inherited Destroy;
end;

function TsgConverterExtented.GetIndexHandle(const AValue: string): Integer;
var
  vPos: Integer;
  vValue: string;
begin
  Result := -1;
  vValue := AValue;
  vPos := AnsiPos(cnstSignHandle, vValue);
  if vPos > 0 then
  begin
    vValue := Copy(vValue, vPos + 1, Length(vValue) - vPos);
    Result := StrToInt(vValue);
  end;
  if Result >= cnstMaxSaveHandleXML then
    Result := cnstMaxSaveHandleXMLError;
end;

function TsgConverterExtented.RestoreHandle(const AExtendHandle: string): Int64;
var
  vIndex: Integer;
begin
  Result := cnstBadHandle;
  vIndex := GetIndexHandle(AExtendHandle);
  if (vIndex >= 0) and (vIndex < cnstMaxSaveHandleXML) then
  begin
    Result := FHandleArray[vIndex];
  end
  else if vIndex < 0 then
    Result := StrToInt64(AExtendHandle);
end;

procedure TsgConverterExtented.SaveHandle(const AValue: string;
  const AEntity: TsgDXFEntity);
var
  vIndex: Integer;
begin
  vIndex := GetIndexHandle(AValue);
  if (vIndex >= 0) and (vIndex < cnstMaxSaveHandleXML) then
  begin
    FOwner.SetHandle(AEntity);
    FHandleArray[vIndex] := AEntity.Handle;
  end;
end;

{ TCustomAlignedDataReader }

constructor TCustomAlignedDataReader.Create(APos: Pointer;
  AVersion: TsgDWGVersion);
begin
  inherited Create;
  FVersion := AVersion;
  FPos := APos;
  FStack := APos;
end;

procedure TCustomAlignedDataReader.PopPosition;
begin
  FPos := FStack;
end;

function TCustomAlignedDataReader.Position: Pointer;
begin
  Result := FPos;
end;

procedure TCustomAlignedDataReader.PushPosition;
begin
  FStack := FPos;
end;

function TCustomAlignedDataReader.ReadByte: Byte;
begin
  Result := PByte(FPos)^;
  Inc(PByte(FPos), SizeOf(Result));
end;

function TCustomAlignedDataReader.ReadDouble: Double;
begin
  Result := PDouble(FPos)^;
  Inc(PByte(FPos), SizeOf(Result));
end;

function TCustomAlignedDataReader.ReadInteger: Integer;
begin
  Result := PInteger(FPos)^;
  Inc(PByte(FPos), SizeOf(Result));
end;

procedure TCustomAlignedDataReader.ReadRaw(const ALen: Integer;
  var AStr: sgRawByteString);
begin
  if ALen > 0 then
  begin
    SetLength(AStr, ALen);
    ReadBytes(AStr[1], ALen);
  end
  else
    AStr := '';
end;

function TCustomAlignedDataReader.ReadSmallInt: SmallInt;
begin
  Result := PSmallInt(FPos)^;
  Inc(PByte(FPos), SizeOf(Result));
end;

procedure TCustomAlignedDataReader.Seek(ASize: Integer);
begin
  Inc(PByte(FPos), ASize);
end;

procedure TCustomAlignedDataReader.ReadBytes(var Dest; const ACount: UInt64);
begin
  Move(FPos^, Dest, ACount);
  Inc(PByte(FPos), ACount);
end;

function TCustomAlignedDataReader.ReadHandle: UInt64;
begin
  Result := PUInt64(FPos)^;
  Inc(PByte(FPos), SizeOf(Result));
end;

function TCustomAlignedDataReader.ReadAnsiPadding: AnsiString;
var
  vLength, vPadding: Integer;
  vSymbol: AnsiChar;
begin
  Result := '';
  vLength := 1;
  vSymbol := AnsiChar(ReadByte);
  while vSymbol <> #0 do
  begin
    Result := Result + vSymbol;
    vSymbol := AnsiChar(ReadByte);
    Inc(vLength);
  end;
  vPadding := vLength and $3;
  Seek(Ord(vPadding <> 0) * 4 - vPadding);
end;

function TCustomAlignedDataReader.ReadString: string;
var
  vLen: Integer;
{$IFDEF SGDEL_2009}
  vCodaPage: Cardinal;
{$ENDIF}
  vWide: WideString;
  vAnsi: sgRawByteString;
begin
  vLen := ReadSmallInt;
  if Version >= acR2007 then
  begin
    ReadWideRaw(vLen, vWide);
    Result := string(vWide);
  end
  else
  begin
{$IFDEF SGDEL_2009}
    vCodaPage := sgCodePageFromDWG(ReadByte);
    SetCodePage(vAnsi, $FFFF, False);
    ReadRaw(vLen, vAnsi);
    SetCodePage(vAnsi, vCodaPage, False);
    Result := string(vAnsi);
{$ELSE}
    Seek(1);
    ReadRaw(vLen, Result);
{$ENDIF}
  end;
end;

procedure TCustomAlignedDataReader.ReadWideRaw(const ALen: Integer;
  var AStr: WideString);
begin
  if ALen > 0 then
  begin
    SetLength(AStr, ALen);
    ReadBytes(AStr[1], ALen shl 1);
  end
  else
    AStr := '';
end;

function TCustomAlignedDataReader.ReadWord: Word;
begin
  Result := PWord(FPos)^;
  Inc(PByte(FPos), SizeOf(Result));
end;

{ TsgDXFXRecord }

constructor TsgDXFXRecord.Create;
begin
  inherited Create;
  FData := TsgCADExtendedData.Create;
end;

procedure TsgDXFXRecord.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFXRecord then
    Data := TsgDXFXRecord(Source).Data;
end;

procedure TsgDXFXRecord.ClearReferences;
begin
  inherited ClearReferences;
  TsgCADExtendedDataAccess(FData).ClearData;
end;

procedure TsgDXFXRecord.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FData);
end;

function TsgDXFXRecord.GetExtData(const AData: TsgCADExtendedData): Boolean;
begin
  AData.AssignData(FData);
  Result := AData.DataCount > 0;
end;

procedure TsgDXFXRecord.SetExtData(const AData: TsgCADExtendedData);
begin
  FData.AssignData(AData);
end;

{ TsgDXFCustomColor }

procedure TsgDXFCustomColor.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFCustomColor then
    ColorCAD := TsgDXFCustomColor(Source).ColorCAD;
end;

function TsgDXFCustomColor.GetColorCAD: TsgColorCAD;
begin
  Result := FColor;
end;

procedure TsgDXFCustomColor.SetColorCAD(const Value: TsgColorCAD);
begin
  FColor := Value;
end;

function TsgDXFCustomColor.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes = []): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[xmlColor].Name).ValueData.ValueAsColorCAD
    := ColorCAD;
end;

function TsgDXFCustomColor.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode = nil): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    xmlColor:
      ColorCAD := ANode.ValueData.ValueAsColorCAD;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

{ TsgCustomMaterialColor }

constructor TsgCustomMaterialColor.Create;
begin
  inherited Create;
end;

function TsgCustomMaterialColor.GetColor: TsgColorCAD;
begin
  Result := cnstDefHeadVarStruct.CEColor;
end;

function TsgCustomMaterialColor.GetFactor: Double;
begin
  Result := 1.0;
end;

function TsgCustomMaterialColor.GetMethod: Integer;
begin
  Result := 0;
end;

procedure TsgCustomMaterialColor.SetColor(const Value: TsgColorCAD);
begin
end;

procedure TsgCustomMaterialColor.SetFactor(const Value: Double);
begin
end;

procedure TsgCustomMaterialColor.SetMethod(const Value: Integer);
begin
end;

{ TsgMaterialColor }

procedure TsgMaterialColor.Assign(Source: TPersistent);
begin
  if Source is TsgMaterialColor then
  begin
    FColor := TsgMaterialColor(Source).FColor;
    FFactor := TsgMaterialColor(Source).FFactor;
    FMethod := TsgMaterialColor(Source).FMethod;
  end
  else
    inherited Assign(Source);
end;

constructor TsgMaterialColor.Create;
begin
  inherited Create;
  FColor := cnstDefHeadVarStruct.CEColor;
  FFactor := 1.0;
  FMethod := 0;
end;

function TsgMaterialColor.GetColor: TsgColorCAD;
begin
  Result := FColor;
end;

function TsgMaterialColor.GetFactor: Double;
begin
  Result := FFactor;
end;

function TsgMaterialColor.GetMethod: Integer;
begin
  Result := FMethod;
end;

procedure TsgMaterialColor.SetColor(const Value: TsgColorCAD);
begin
  FColor := Value;
end;

procedure TsgMaterialColor.SetFactor(const Value: Double);
begin
  FFactor := Value;
end;

procedure TsgMaterialColor.SetMethod(const Value: Integer);
begin
  FMethod := Value;
end;

{ TsgMaterialMap }

procedure TsgMaterialMap.Assign(Source: TPersistent);
begin
  if Source is TsgMaterialMap then
  begin
    FBlend := TsgMaterialMap(Source).FBlend;
    FFileName := TsgMaterialMap(Source).FFileName;
    FMapSource := TsgMaterialMap(Source).FMapSource;
    Mapper := TsgMaterialMap(Source).Mapper;
    MaterialColor := TsgMaterialMap(Source).MaterialColor;
    Xrecord := TsgMaterialMap(Source).Xrecord;
  end
  else
    inherited Assign(Source);
end;

constructor TsgMaterialMap.Create;
begin
  inherited Create;
  FBlend := 1.0;
  FMapSource := 0;
  FMapper := TsgMaterialMapper.Create;
  FMaterialColor := CreateMaterialColor;
  FXrecordItem := TsgTableItem.Create;
end;

function TsgMaterialMap.CreateMaterialColor: TsgCustomMaterialColor;
begin
  Result := TsgCustomMaterialColor.Create;
end;

destructor TsgMaterialMap.Destroy;
begin
  FMapper.Free;
  FMaterialColor.Free;
  FXrecordItem.Item := nil;
  FXrecordItem.Free;
  inherited Destroy;
end;

function TsgMaterialMap.GetXrecord: TsgDXFXRecord;
begin
  Result := TsgDXFXRecord(FXrecordItem.Item);
end;

procedure TsgMaterialMap.SetBlend(const Value: Double);
begin
  FBlend := Value;
end;

procedure TsgMaterialMap.SetFileName(const Value: string);
begin
  FFileName := Value;
end;

procedure TsgMaterialMap.SetMapper(const Value: TsgMaterialMapper);
begin
  FMapper.Assign(Value);
end;

procedure TsgMaterialMap.SetMapSource(const Value: Integer);
begin
  FMapSource := Value;
end;

procedure TsgMaterialMap.SetMaterialColor(const Value: TsgCustomMaterialColor);
begin
  FMaterialColor.Assign(Value);
end;

procedure TsgMaterialMap.SetXrecord(const Value: TsgDXFXRecord);
begin
  FXrecordItem.Item := Value;
end;

{ TsgMaterialMapper }

procedure TsgMaterialMapper.Assign(Source: TPersistent);
begin
  if Source is TsgMaterialMapper then
  begin
    FAutoTransform := TsgMaterialMapper(Source).FAutoTransform;
    FTransform := TsgMaterialMapper(Source).FTransform;
    FProjection := TsgMaterialMapper(Source).FProjection;
    FTiling := TsgMaterialMapper(Source).FTiling;
  end
  else
    inherited Assign(Source);
end;

constructor TsgMaterialMapper.Create;
begin
  inherited Create;
  FTransform.M[0, 0] := 1.0;
  FTransform.M[1, 1] := 1.0;
  FTransform.M[2, 2] := 1.0;
  FTransform.M[3, 3] := 1.0;
end;

function TsgMaterialMapper.GetAsAddress: PSingle;
begin
  Result := @FTransform.M[0, 0];
end;

function TsgMaterialMapper.GetMatrix(I, J: Integer): Single;
begin
  Result := FTransform.M[I, J];
end;

procedure TsgMaterialMapper.SetAutoTransform(const Value: Byte);
begin
  FAutoTransform := Value;
end;

procedure TsgMaterialMapper.SetMatrix(I, J: Integer; const Value: Single);
begin
  FTransform.M[I, J] := Value;
end;

procedure TsgMaterialMapper.SetProjection(const Value: Byte);
begin
  FProjection := Value;
end;

procedure TsgMaterialMapper.SetTiling(const Value: Byte);
begin
  FTiling := Value;
end;

procedure TsgMaterialMapper.SetTransform(const Value: TsgTexMatrix4f);
begin
  FTransform := Value;
end;

{ TsgDXFMaterial }

procedure TsgDXFMaterial.AssignEntity(Source: TsgDXFEntity);
begin
  inherited AssignEntity(Source);
  if Source is TsgDXFMaterial then
  begin
    Ambient := TsgDXFMaterial(Source).Ambient;
    Diffuse := TsgDXFMaterial(Source).Diffuse;
    Specular := TsgDXFMaterial(Source).Specular;
    Reflection := TsgDXFMaterial(Source).Reflection;
    Opacity := TsgDXFMaterial(Source).Opacity;
    Bump := TsgDXFMaterial(Source).Bump;
    Refraction := TsgDXFMaterial(Source).Refraction;
  end;
end;

constructor TsgDXFMaterial.Create;
begin
  inherited Create;
  FAmbient := TsgAmbientMaterialMap.Create;
  FDiffuse := TsgDiffuseMaterialMap.Create;
  FSpecular := TsgSpecularMaterialMap.Create;
  FReflection := TsgReflectionMaterialMap.Create;
  FOpacity := TsgOpacityMaterialMap.Create;
  FBump := TsgBumpMaterialMap.Create;
  FRefraction := TsgRefractionMaterialMap.Create;
end;

procedure TsgDXFMaterial.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FAmbient);
  FreeAndNil(FDiffuse);
  FreeAndNil(FSpecular);
  FreeAndNil(FReflection);
  FreeAndNil(FOpacity);
  FreeAndNil(FBump);
  FreeAndNil(FRefraction);
end;

procedure TsgDXFMaterial.SetAmbient(const Value: TsgAmbientMaterialMap);
begin
  FAmbient.Assign(Value);
end;

procedure TsgDXFMaterial.SetBump(const Value: TsgBumpMaterialMap);
begin
  FBump.Assign(Value);
end;

procedure TsgDXFMaterial.SetDiffuse(const Value: TsgDiffuseMaterialMap);
begin
  FDiffuse.Assign(Value);
end;

procedure TsgDXFMaterial.SetOpacity(const Value: TsgOpacityMaterialMap);
begin
  FOpacity.Assign(Value);
end;

procedure TsgDXFMaterial.SetReflection(const Value: TsgReflectionMaterialMap);
begin
  FReflection.Assign(Value);
end;

procedure TsgDXFMaterial.SetRefraction(const Value: TsgRefractionMaterialMap);
begin
  FRefraction.Assign(Value);
end;

procedure TsgDXFMaterial.SetSpecular(const Value: TsgSpecularMaterialMap);
begin
  FSpecular.Assign(Value);
end;

{ TsgSpecularMaterialMap }

procedure TsgSpecularMaterialMap.Assign(Source: TPersistent);
begin
  if Source is TsgSpecularMaterialMap then
  begin
    FGloss := TsgSpecularMaterialMap(Source).FGloss;
  end;
  inherited Assign(Source);
end;

constructor TsgSpecularMaterialMap.Create;
begin
  inherited Create;
  FGloss := 0.5;
end;

procedure TsgSpecularMaterialMap.SetGloss(const Value: Double);
begin
  FGloss := Value;
end;

{ TsgColoredMaterialMap }

function TsgColoredMaterialMap.CreateMaterialColor: TsgCustomMaterialColor;
begin
  Result := TsgMaterialColor.Create;
end;

{ TsgRefractionMaterialMap }

procedure TsgRefractionMaterialMap.Assign(Source: TPersistent);
begin
  if Source is TsgRefractionMaterialMap then
  begin
    FIndex := TsgRefractionMaterialMap(Source).FIndex;
  end;
  inherited Assign(Source);
end;

procedure TsgRefractionMaterialMap.SetIndex(const Value: Double);
begin
  FIndex := Value;
end;

{ TsgDiffuseMaterialMap }

procedure TsgDiffuseMaterialMap.Assign(Source: TPersistent);
begin
  if Source is TsgDiffuseMaterialMap then
  begin
    Bleed := TsgDiffuseMaterialMap(Source).Bleed;
    IndirectDump := TsgDiffuseMaterialMap(Source).IndirectDump;
    Normal1 := TsgDiffuseMaterialMap(Source).Normal1;
    Normal2 := TsgDiffuseMaterialMap(Source).Normal2;
    FReflectanceScale := TsgDiffuseMaterialMap(Source).FReflectanceScale;
    FLuminance := TsgDiffuseMaterialMap(Source).FLuminance;
    FTransmittanceScale := TsgDiffuseMaterialMap(Source).FTransmittanceScale;
  end;
  inherited Assign(Source);
end;

constructor TsgDiffuseMaterialMap.Create;
begin
  inherited Create;
  FBleed := CreateMaterialColor;
  FIndirectDump := CreateMaterialColor;
  FNormal1 := CreateMaterialColor;
  FNormal2 := CreateMaterialColor;
end;

destructor TsgDiffuseMaterialMap.Destroy;
begin
  FBleed.Free;
  FIndirectDump.Free;
  FNormal1.Free;
  FNormal2.Free;
  inherited Destroy;
end;

procedure TsgDiffuseMaterialMap.SetBleed(const Value: TsgCustomMaterialColor);
begin
  FBleed.Assign(Value);
end;

procedure TsgDiffuseMaterialMap.SetIndirectDump(const Value
  : TsgCustomMaterialColor);
begin
  FIndirectDump.Assign(Value);
end;

procedure TsgDiffuseMaterialMap.SetLuminance(const Value: Double);
begin
  FLuminance := Value;
end;

procedure TsgDiffuseMaterialMap.SetNormal1(const Value: TsgCustomMaterialColor);
begin
  FNormal1.Assign(Value);
end;

procedure TsgDiffuseMaterialMap.SetNormal2(const Value: TsgCustomMaterialColor);
begin
  FNormal2.Assign(Value);
end;

procedure TsgDiffuseMaterialMap.SetReflectanceScale(const Value: Double);
begin
  FReflectanceScale := Value;
end;

procedure TsgDiffuseMaterialMap.SetTransmittanceScale(const Value: Double);
begin
  FTransmittanceScale := Value;
end;

{ TsgOpacityMaterialMap }

procedure TsgOpacityMaterialMap.Assign(Source: TPersistent);
begin
  if Source is TsgOpacityMaterialMap then
  begin
    FPercent := TsgOpacityMaterialMap(Source).FPercent;
  end;
  inherited Assign(Source);
end;

constructor TsgOpacityMaterialMap.Create;
begin
  inherited Create;
  FPercent := 1.0;
end;

procedure TsgOpacityMaterialMap.SetPercent(const Value: Double);
begin
  FPercent := Value;
end;

{ TsgDXFScale }

constructor TsgDXFScale.Create;
begin
  inherited Create;
  FLayoutScale := 1;
  FModelScale := 1;
  FDescription := '1:1';
end;

function TsgDXFScale.FromXMLNode(const AType: TsgXMLType;
  const ANode: TsgNodeSample; const AIsChild: Boolean;
  const AResult: IsgResultNode): Integer;
begin
  Result := inherited FromXMLNode(AType, ANode, AIsChild, AResult);
  if Result <> cnstXML_UNSUPPORTED then
    Exit;
  Result := cnstXML_OK;
  case AType.ID of
    sgConsts.xmlDescription:
      Description := ANode.ValueAsStr;
    xmlLayoutScale:
      LayoutScale := ANode.ValueAsDouble;
    xmlModelScale:
      ModelScale := ANode.ValueAsDouble;
  else
    Result := cnstXML_UNSUPPORTED;
  end;
end;

procedure TsgDXFScale.SetDescription(const AValue: string);
begin
  FDescription := AValue;
end;

procedure TsgDXFScale.SetLayoutScale(const AValue: Double);
begin
  FLayoutScale := AValue;
end;

procedure TsgDXFScale.SetModelScale(const AValue: Double);
begin
  FModelScale := AValue;
end;

function TsgDXFScale.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  ANode.AddAttribNV(cnstXMLNames[sgConsts.xmlDescription].Name).Value :=
    Description;
  ANode.AddAttribNV(cnstXMLNames[xmlLayoutScale].Name).ValueAsDouble :=
    LayoutScale;
  ANode.AddAttribNV(cnstXMLNames[xmlModelScale].Name).ValueAsDouble :=
    ModelScale;
end;

{ TsgDXFObjectContextData }

procedure TsgDXFObjectContextData.ClearReferences;
begin
  inherited ClearReferences;
  Scale := nil;
end;

constructor TsgDXFObjectContextData.Create;
begin
  inherited Create;
  FScaleItem := TsgTableItem.Create;
end;

procedure TsgDXFObjectContextData.FreeReferences;
begin
  inherited FreeReferences;
  FreeAndNil(FScaleItem);
end;

function TsgDXFObjectContextData.GetScale: TsgDXFScale;
begin
  Result := TsgDXFScale(FScaleItem.Item);
end;

procedure TsgDXFObjectContextData.SetScale(const Value: TsgDXFScale);
begin
  FScaleItem.Item := Value;
end;

function TsgDXFObjectContextData.ToXMLNode(const ANode: TsgNode;
  const AMode: TsgXMLModes): Integer;
begin
  Result := inherited ToXMLNode(ANode, AMode);
  if Scale <> nil then
    ANode.AddAttribNV(cnstXMLNames[xmlScale].Name).ValueAsStr := Scale.Name;
end;

{ TsgDictionaryItem }

constructor TsgDictionaryItem.Create(AEntity: TsgDXFEntity);
begin
  inherited Create;
  FEntity := AEntity;
end;

initialization

GlobalCheckNameLayer := True;
LoadEntityProc := nil;
ExternalEntities := nil;
StdLines := TsgLines.Create;
MacroStrings := TStringList.Create;
GlobalLoadingXRefsStack := TThreadList.Create;
XRefFileClasses := TsgStringList.Create;
TsgStringList(XRefFileClasses).CaseSensitive := False;
TsgStringList(XRefFileClasses).Sorted := True;

GlobalsgTypes.AddClass(Tsg2DCurve);
GlobalsgTypes.AddClass(Tsg2DLine);
GlobalsgTypes.AddClass(Tsg2DArc);
GlobalsgTypes.AddClass(Tsg2DPoints);
GlobalsgTypes.AddClass(Tsg2DPolyline);
GlobalsgTypes.AddClass(Tsg2DBoundaryList);
GlobalsgTypes.AddClass(TsgCADHatch);
GlobalsgTypes.AddClass(TsgCADPolyPolygon);
GlobalsgTypes.AddClass(TsgCADGradientPolygon);
GlobalsgTypes.AddClass(TsgCADHelix);
GlobalsgTypes.AddClass(TsgCADMPolygon);
GlobalsgTypes.AddClass(TsgCADFill);
GlobalsgTypes.AddClass(TsgCADWipeout);
GlobalsgTypes.AddClass(TsgDXFAcadTable);
GlobalsgTypes.AddClass(TsgDXFAcadTableStyle);
GlobalsgTypes.AddClass(TsgDXFArc);
GlobalsgTypes.AddClass(TsgDXFAttdef);
GlobalsgTypes.AddClass(TsgDXFAttrib);
GlobalsgTypes.AddClass(TsgDXFBlock);
GlobalsgTypes.AddClass(TsgDXFDimensionStyle);
GlobalsgTypes.AddClass(TsgDXFConverter);
GlobalsgTypes.AddClass(TsgDXFCircle);
GlobalsgTypes.AddClass(TsgDXFDictionary);
GlobalsgTypes.AddClass(TsgDXFDimension);
GlobalsgTypes.AddClass(TsgDXFEntity);
GlobalsgTypes.AddClass(TsgDXFEllipse);
GlobalsgTypes.AddClass(TsgDXFField);
GlobalsgTypes.AddClass(TsgDXFFieldList);
GlobalsgTypes.AddClass(TsgDXFGroup);
GlobalsgTypes.AddClass(TsgDXFInsert);
GlobalsgTypes.AddClass(TsgDXFImageDef);
GlobalsgTypes.AddClass(TsgDXFImageEnt);
GlobalsgTypes.AddClass(TsgDXFLayer);
GlobalsgTypes.AddClass(TsgDXFLayout);
GlobalsgTypes.AddClass(TsgDXFLeader);
GlobalsgTypes.AddClass(TsgDXFLine);
GlobalsgTypes.AddClass(TsgDXFLineType);
GlobalsgTypes.AddClass(TsgDXFLWPolyline);
GlobalsgTypes.AddClass(TsgDXFMText);
GlobalsgTypes.AddClass(TsgDXFObjectEntity);
GlobalsgTypes.AddClass(TsgDXFOle2Frame);
GlobalsgTypes.AddClass(TsgDXFOwneredItem);
GlobalsgTypes.AddClass(TsgDXFPoint);
GlobalsgTypes.AddClass(TsgDXFPolyline);
GlobalsgTypes.AddClass(TsgDXFProxy);
GlobalsgTypes.AddClass(TsgDXFSection);
GlobalsgTypes.AddClass(TsgDXFSolid);
GlobalsgTypes.AddClass(TsgDXFSortEntsTable);
GlobalsgTypes.AddClass(TsgDXFSpline);
GlobalsgTypes.AddClass(TsgDXFTable);
GlobalsgTypes.AddClass(TsgDXFText);
GlobalsgTypes.AddClass(TsgDXFStyle);
GlobalsgTypes.AddClass(TsgDXFVertex);
GlobalsgTypes.AddClass(TsgDXFViewport);
GlobalsgTypes.AddClass(TsgDXFVport);
GlobalsgTypes.AddClass(TsgDXFXref);
GlobalsgTypes.AddClass(TsgDXFInsertXRef);
GlobalsgTypes.AddClass(TsgDXFSectionHeader);
GlobalsgTypes.AddClass(TsgDXFSectionTables);
GlobalsgTypes.AddClass(TsgDXFBlockRecords);
GlobalsgTypes.AddClass(TsgDXFSectionBlocks);
GlobalsgTypes.AddClass(TsgDXFSectionObjects);
GlobalsgTypes.AddClass(TsgDXFSectionEntities);
GlobalsgTypes.AddClass(TsgDXFPenTableItem);
GlobalsgTypes.Sort;

finalization

XRefFileClasses.Free;
GlobalLoadingXRefsStack.Free;
StdLines.Free;
MacroStrings.Free;
ExternalEntitiesFree;

end.
