{************************************************************}
{                 Delphi VCL Extensions                      }
{                                                            }
{             B-rep model supporting classes                 }
{                                                            }
{         Copyright (c) 2012-2013 SoftGold software company  }
{                                                            }
{************************************************************}

unit sgBrepConverter;
{$INCLUDE SGDXF.INC}
//{$DEFINE SG_BREP_DEBUG}
//{$DEFINE CHECK_TIME}

// To be able to get volume, add a DIRECTIVE in SGDXF.INC - {$DEFINE SG_BREP_TOPOLOGY}
// MeshBuilder - Must be assembled with #define CALC_MASS
interface

uses
  Windows, SysUtils, Classes, Graphics, Math, sgConsts,  SGLines, sgFunction, sgLists,
  sgComparer, DXFConv, sgMeshBuilderWrapper;

type
  TsgEntityBrep = class(TsgDXFEntity)
{$IFDEF SG_BREP_DEBUG}
  private
    FIndex: Integer;
{$ENDIF}
  protected
    function GetBrepEntType: TsgBrepEntities; virtual;
  public
    property BrepEntType: TsgBrepEntities read GetBrepEntType;
  end;

  //Topology B-rep
  TsgBrepLump = class;
  TsgBrepWire = class;
  TsgBrepShell = class;
  TsgBrepFace = class;
  TsgBrepSubShell = class;
  TsgBrepLoop = class;
  TsgBrepCoEdge = class;
  TsgBrepEdge = class;
  TsgBrepVertices = class;

  //Geometry B-rep
  TsgBrepSurface = class;
  TsgBrepCurve = class;
  TsgBrepEllipsCurve = class;

  TsgEntityBrepTopology = class(TsgEntityBrep)
  private
    FOwned: TsgEntityBrepTopology;
    FOrientation: Integer;
  protected
    FChildren: TList;
    function Add(AType: TsgDXFEntityClass): TsgEntityBrepTopology;
    function Owner: TsgEntityBrepTopology; virtual;
  public
    constructor Create; override;
    destructor Destroy; override;
    property Orientation: Integer read FOrientation;
  end;

  TsgEntityBrepTwo = class(TsgEntityBrepTopology)
  private
  protected
    FChildrenTwo: TList;
    function AddTwo(AType: TsgDXFEntityClass): TsgEntityBrepTopology;
  public
    constructor Create; override;
    destructor Destroy; override;
  end;

  TsgEntityBrepThree = class(TsgEntityBrepTwo)
  private
  protected
    FChildrenThree: TList;
    function AddThree(AType: TsgDXFEntityClass): TsgEntityBrepTopology;
  public
    constructor Create; override;
    destructor Destroy; override;
  end;

  TsgBody = class(TsgEntityBrepTopology)
  private
    FMatrix: TFMatrix;
    FMatrixPlus: Double;
  public
    function AddLump: TsgBrepLump;
    property Lumps: TList read FChildren;
    property Matrix: TFMatrix read FMatrix;
    property MatrixPlus: Double read FMatrixPlus;
  end;

  TsgBrepLump = class(TsgEntityBrepTopology)
  public
    function AddShell: TsgBrepShell;
    property Shell: TList read FChildren;
  end;

  TsgBrepSubShell = class(TsgEntityBrepTwo)
  public
    property Face: TList read FChildren;
    property Wire: TList read FChildrenTwo;
  end;

  TsgBrepShell = class(TsgEntityBrepThree)
  public
    function AddFace: TsgBrepFace;
    function AddWire: TsgBrepWire;
    function AddSubShell: TsgBrepSubShell;
    property Face: TList read FChildren;
    property Wire: TList read FChildrenTwo;
    property SubShell: TList read FChildrenThree;
  end;

  TsgBrepFace = class(TsgEntityBrepTopology)
  private
    FSufface: TsgBrepSurface;
    FContext: TsgContext;
  public
    constructor Create; override;
    destructor Destroy; override;
    function AddLoop: TsgBrepLoop;
    function GetContex: PsgContext;
    property Loops: TList read FChildren;
    property Sufface: TsgBrepSurface read FSufface write FSufface;
  end;

  TsgBrepLoop = class(TsgEntityBrepTopology)
  public
    function AddCoEdge: TsgBrepCoEdge;
    property CoEdges: TList read FChildren;
  end;

  TsgBrepWire = class(TsgBrepLoop)
  end;

  TsgBrepCoEdge = class(TsgEntityBrepTopology)
  public
    function AddEdge: TsgBrepEdge;
    property Edges: TList read FChildren;
  end;

  TsgBrepEdge = class(TsgEntityBrepTopology)
  private
    FPointA: TFPoint;
    FPointB: TFPoint;
    FStartParam: Double;
    FEndParam: Double;
    FCurve: TsgBrepCurve;
  public
    constructor Create; override;
    destructor Destroy; override;
    function AddVertice: TsgBrepVertices;
    property StartParam: Double read FStartParam write FStartParam;
    property EndParam: Double read FEndParam write FEndParam;
    property Vertices: TList read FChildren;
    property Curve: TsgBrepCurve read FCurve write FCurve;
  end;

  TsgBrepVertices = class(TsgEntityBrepTopology)
  private
//    FPoints: TFPointList;//for future version
  end;

  TsgBrepEntityGeometry = class(TsgEntityBrep)
  protected
    function GetBrepEntType: TsgBrepEntities; override;
  end;

  TsgBrepSurface = class(TsgBrepEntityGeometry)
  end;

  TsgBrepPlaneSurface = class(TsgBrepSurface)
  private
    FRootPoint: TFPoint;
    FNormal: TFPoint;
    FUDeriv: TFPoint;
    FReverseV: Boolean;
  protected
    function GetBrepEntType: TsgBrepEntities; override;
  public
    property RootPoint: TFPoint read FRootPoint write FRootPoint;
    property Normal: TFPoint read FNormal write FNormal;
    property UDeriv: TFPoint read FUDeriv write FUDeriv;
    property ReverseV: Boolean read FReverseV write FReverseV;
  end;

  TsgBrepConeSurface = class(TsgBrepSurface)
  private
    FBase: TsgBrepEllipsCurve;
    FCosineAngle: Double;
    FSineAngle: Double;
    FReverseU: Boolean;
    FUParamScale: Double;
  protected
    function GetBrepEntType: TsgBrepEntities; override;
  public
    constructor Create; override;
    destructor Destroy; override;
    property Base: TsgBrepEllipsCurve read FBase write FBase;
    property CosineAngle: Double read FCosineAngle write FCosineAngle;
    property SineAngle: Double read FSineAngle write FSineAngle;
    property ReverseU: Boolean read FReverseU write FReverseU;
    property UParamScale: Double read FUParamScale write FUParamScale;
  end;

  TsgBrepSphereSurface = class(TsgBrepSurface)
  private
    FCenter: TFPoint;
    FRadius: Double;
    FUVOridir: TFPoint;
    FPoleDir: TFPoint;
    FReverseV: Boolean;
  protected
    function GetBrepEntType: TsgBrepEntities; override;
  public
    property Center: TFPoint read FCenter write FCenter;
    property Radius: Double read FRadius write FRadius;
    property UVOridir: TFPoint read FUVOridir write FUVOridir;
    property PoleDir: TFPoint read FPoleDir write FPoleDir;
    property ReverseV: Boolean read FReverseV write FReverseV;
  end;

  TsgBrepTorusSurface = class(TsgBrepSurface)
  private
    FCenter: TFPoint;
    FNormal: TFpoint;
    FMajorRadius: Double;
    FMinorRadius: Double;
    FUVOridir: TFPoint;
    FReverseV: Boolean;
  protected
    function GetBrepEntType: TsgBrepEntities; override;
  public
    property Center: TFPoint read FCenter write FCenter;
    property Normal: TFPoint read FNormal write FNormal;
    property MajorRadius: Double read FMajorRadius write FMajorRadius;
    property MinorRadius: Double read FMinorRadius write FMinorRadius;
    property UVOridir: TFPoint read FUVOridir write FUVOridir;
    property ReverseV: Boolean read FReverseV write FReverseV;
  end;

  TsgBrepBs3Surface = class(TsgBrepSurface)
  private
    FDegree: Integer;
    FIdentClosere: Integer;
    FIdentSingularities: Integer;
    FControlPoints: TFPointList;
    FKnots: TsgDoubleList;
    FMultiplicities: TsgIntegerList;
    FWeights: TsgDoubleList;
  public
    constructor Create; override;
    destructor Destroy; override;
    property Degree: Integer read FDegree write FDegree;
    property IdentClosere: Integer read FIdentClosere write FIdentClosere;
    property IdentSingularities: Integer read FIdentSingularities write FIdentSingularities;
    property ControlPoints: TFPointList read FControlPoints write FControlPoints;
    property Knots: TsgDoubleList read FKnots write FKnots;
    property Multiplicities: TsgIntegerList read FMultiplicities write FMultiplicities;
    property Weights: TsgDoubleList read FWeights write FWeights;
  end;

  TsgBrepSplineSurface = class(TsgBrepSurface)
  public
  end;

  // NURBS surface
  TsgBrepExactSplineSurface = class(TsgBrepSplineSurface)
  private
    FBs3SurfaceU: TsgBrepBs3Surface;
    FBs3SurfaceV: TsgBrepBs3Surface;
    FControlPointsUV: TFPointList;
    FWeightsUV: TsgDoubleList;
  protected
    function GetBrepEntType: TsgBrepEntities; override;
  public
    constructor Create; override;
    destructor Destroy; override;
    property Bs3SurfaceU: TsgBrepBs3Surface read FBs3SurfaceU;
    property Bs3SurfaceV: TsgBrepBs3Surface read FBs3SurfaceV;
    property ControlPointsUV: TFPointList read FControlPointsUV write FControlPointsUV;
    property WeightsUV: TsgDoubleList read FWeightsUV write FWeightsUV;
  end;

  TsgBrepIntervalType = (itUnknown, itFinite, itFiniteBelow, itFiniteAbove,
     itInfinite);

  TsgBrepInterval = class(TsgBrepEntityGeometry)
  private
    FIntervalType: TsgBrepIntervalType;
    FRangeaA: Double;
    FRangeaB: Double;
  public
    property IntervalType: TsgBrepIntervalType read FIntervalType
      write FIntervalType;
    property RangeaA: Double read FRangeaA write FRangeaA;
    property RangeaB: Double read FRangeaB write FRangeaB;
  end;

  TsgBrepCurve = class(TsgBrepInterval)
  end;

  TsgBrepEllipsCurve = class(TsgBrepCurve)
  private
    FCenter: TFPoint;
    FMajorAxis: TFPoint;
    FNormal: TFPoint;
    FParamOff: Double;
    FRadiusRatio: Double;
  protected
    function GetBrepEntType: TsgBrepEntities; override;
  public
    property Center: TFPoint read FCenter write FCenter;
    property MajorAxis: TFPoint read FMajorAxis write FMajorAxis;
    property Normal: TFPoint read FNormal write FNormal;
    property ParamOff: Double read FParamOff write FParamOff;
    property RadiusRatio: Double read FRadiusRatio write FRadiusRatio;
  end;

  TsgBrepStraightCurve = class(TsgBrepCurve)
  private
    FDirection: TFPoint;
    FParamScale: Double;
    FRoot:TFPoint;
  protected
    function GetBrepEntType: TsgBrepEntities; override;
  public
    property Direction: TFPoint read FDirection write FDirection;
    property ParamScale: Double read FParamScale write FParamScale;
    property Root: TFPoint read FRoot write FRoot;
  end;

  TsgBrepHelixCurve = class(TsgBrepCurve)//for future version
  private
//    FAxisRoot: TFpoint;
//    FAxisDir: TFPoint;
//    FStartDisp: TFPoint;
//    FPitch: Double;
//    FHandedness: Double;
//    FParScaling: Double;
//    FTaper: Double;
//    FHelixRange: TsgBrepInterval;
  protected
    function GetBrepEntType: TsgBrepEntities; override;
  end;

  TsgBrepBs2Curve = class(TsgBrepCurve)

  end;

  TsgBrepBs3Curve = class(TsgBrepCurve)
  private
    FDegree: Integer;
    FIdentClosere: Integer;
    FControlPoints: TFPointList;
    FKnots: TsgDoubleList;
    FMultiplicities: TsgIntegerList;
    FWeights: TsgDoubleList;
  protected
    function GetBrepEntType: TsgBrepEntities; override;
  public
    constructor Create; override;
    destructor Destroy; override;
    property Degree: Integer read FDegree write FDegree;
    property IdentClosere: Integer read FIdentClosere write FIdentClosere;
    property ControlPoints: TFPointList read FControlPoints write FControlPoints;
    property Knots: TsgDoubleList read FKnots write FKnots;
    property Multiplicities: TsgIntegerList read FMultiplicities write FMultiplicities;
    property Weights: TsgDoubleList read FWeights write FWeights;
  end;

  TsgBrepIntCurve = class(TsgBrepCurve)
  private
  public
    constructor Create; override;
    destructor Destroy; override;
  end;

  TsgBrepExactCurve = class(TsgBrepIntCurve)
  private
    FBs3Curve: TsgBrepBs3Curve;
    FFirstSurface: TsgBrepSurface;
    FSecondSurface: TsgBrepSurface;
    FFirstCurve: TsgBrepCurve;
    FSecondCurve: TsgBrepCurve;
    FFit: TFPointList;
    FRev: Boolean;
    //FDiscInfo:
    //
  protected
    function GetBrepEntType: TsgBrepEntities; override;
  public
    constructor Create; override;
    destructor Destroy; override;
    property Bs3Curve: TsgBrepBs3Curve read FBs3Curve;
    property FirstSurface: TsgBrepSurface read FFirstSurface;
    property SecondSurface: TsgBrepSurface read FSecondSurface;
    property FirstCurve: TsgBrepCurve read FFirstCurve;
    property SecondCurve: TsgBrepCurve read FSecondCurve;
    property Fit: TFPointList read FFit;
    property Rev: Boolean read FRev write FRev;
  end;

  TsgBrepRoot = class(TsgEntityBrep)
  private
    FBody: TList;
  public
    constructor Create; override;
    destructor Destroy; override;
    // OpenCascade link
    function AddSurfaceToBrepBuilder(AContext: PsgContext;
      AFace: TsgBrepFace): Boolean;
    function AddCurveToBrepBuilder(AContext: PsgContext;
      AEdge: TsgBrepEdge; AOrientation: Integer): Boolean;
    property Body: TList read FBody;
  end;

  TsgCreatorEntityBase = class
  private
    FConverter: TsgDXFConverter;
    FBase: TsgDXFEntity;
    FStackBlock: TsgStackObject;
    FCurrentBlock: TsgDXFBlock;
    FCurrentFace: TsgBrepEntity;
{$IFDEF SG_BREP_TOPOLOGY}
    FCurrentTopology: TsgBrepObjectTopology;
    FStackTopology: TsgStackObject;
    FStackInsert: TsgStackObject;
    FCurrentInsert: TsgDXFInsert;
{$ENDIF}
    //FInsertPrev: TsgDXFInsert;
{$IFDEF CHECK_TIME}
    TicksLoad: Cardinal;
    TicksLoadOpenCascade: Cardinal;
    IsCalcTick: Boolean;
{$ENDIF}
{$IFDEF SG_BREP_DEBUG}
    FLevelTab: Integer;
    FStrTab: string;
{$ENDIF}


  protected
    function CreateEntityInternal(const AClass: TClass): TsgDXFEntity;
    function AddEntityInternal(const AEntity: TsgDXFEntity): TsgDXFEntity; virtual;
    function CreateIndexFace(AIndexFace: Integer): TsgBrepEntity; virtual;
{$IFDEF SG_BREP_TOPOLOGY}
    function CreateObjectTopology(ACenterMass: TFPoint;
      AVolume, AArea: Double; AName: string): TsgBrepEntity; virtual;
    procedure SetObjectTopologyFace(AArea: Double); virtual;
{$ENDIF}
  public
    constructor Create(const AConv: TsgDXFConverter; const ABase: TsgDXFEntity);
    destructor Destroy; override;
    function CreateEntity(const AClass: TClass; const AFirstPoint,
      ALastPoint: PFPoint; var IsCreated: Boolean): TsgDXFEntity;
    function GetCurrentParent: TsgDXFEntity;
    function AddEntity(const AEntity: TsgDXFEntity): TsgDXFEntity;
    procedure BeginSegment(const AColor: TsgColorCAD; AIndexFaceMap: Integer = -1;
      Name: String = '');
    procedure EndSegment;
  end;

  TsgSATParser = class;

  TsgSatCreatorEntity = class(TsgCreatorEntityBase)
  private
    FOwner: TsgSATParser;
  protected
    function AddEntityInternal(const AEntity: TsgDXFEntity): TsgDXFEntity; override;
    function CreateIndexFace(AIndexFace: Integer): TsgBrepEntity; override;
{$IFDEF SG_BREP_TOPOLOGY}
    procedure SetObjectTopologyFace(AArea: Double); override;
{$ENDIF}
  public
    constructor CreateEx(const AOwner: TsgSATParser; const ABase: TsgDXFEntity);
  end;

  TsgSATParser = class
  private
    FACIS: TsgDXFACISEntity;
    FSatCreateEntity: TsgSatCreatorEntity;
    FCoEdgeReversed: Boolean;
    FConverter: TsgDXFConverter;
    FPoints: array [0..1] of TFPoint;
    FSATStrings: TStringList;
    FDelimiter: Char;
    FEofStr: Char;
    FBody: TList;
    FBadSurface: Boolean;
    FParsingStatus: Boolean;
    FHeader: TsgSATFileHeader;
    FBodiesIndexes: TsgIntegerList;
    FNeedToDec: Boolean;
    //--> Brep block
    //Curve
    procedure AddEllipseCurve(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
    procedure AddIntCurve(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
    procedure AddStraightCurve(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
    procedure AddHelixCurve(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
    //Surface
    procedure AddConeSurface(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
    procedure AddPlanSurface(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
    procedure AddTorusSurface(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
    procedure AddSphereSurface(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
    procedure AddSplineSurface(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
    // Add geometry to the topology
    function AddBrepLink(ABrepEntity: TsgEntityBrepTopology;
      ASurface: TsgBrepSurface): Boolean; overload;
    function AddBrepLink(ABrepEntity: TsgEntityBrepTopology;
      ACurve: TsgBrepCurve): Boolean; overload;
//    // OpenCascade link
//    function AddSurfaceToBrepBuilder(ASurface: TsgBrepSurface): Boolean;
//    function AddCurveToBrepBuilder(AEdge: TsgBrepEdge): Boolean;
    //<-- End Brep block
    procedure AddEntity(const AEntity: TsgDXFEntity);
    procedure CheckIncorrectAttribs;
    function CreateEntity(const AClass: TClass): TsgDXFEntity;
    function CheckIndex(const Index: Integer): Integer;
    function CheckSatName(const Index: Integer; const Names: array of string): Integer;
    procedure DecodeProprietaryData;
    function GetSATString(const AIndex: Integer): string;
    function GetSATStringsCount: Integer;
    function GetContentData(AIndex: Integer): string;
    function GetPoint(AIndex: Integer): TFPoint;
    function GetSubString(AStr: string; AIndex: Integer): string;
    function GetPosNext(const ASubStr, AStr: string): Integer;
    function GetVertex(AIndex: Integer): TFPoint;
    function GetStatus: Boolean;
    function GetStrWithDataValues(const StrIndex,
      PtRecInxBeforeDataValues: Integer): string;
    function GetNameValueOfString(const StrIndex: Integer): string;
    function GetVersion: Integer;
    function GetFileHeader: TsgSATFileHeader;
    function GetPtInxVertexPoint: Integer;
    function GetPtInxVertexTVertexVertexPoint: Integer;
    function GetPtInxEdgeStartVertex: Integer;
    function GetPtInxEdgeEndVertex: Integer;
    function GetPtInxEdgeCurve: Integer;
    function GetPtInxBodyLump: Integer;
    function GetPtInxBodyTransform: Integer;
    function GetPtInxCoedgeEdge: Integer;
    function GetPtInxCoedgeNextCoedge: Integer;
    function GetPtInxLoopFirstCoedge: Integer;
    function GetPtInxLoopNextLoopInBoundaryOfFace: Integer;
    function GetPtInxFaceFirstLoopBoundingFace: Integer;
    function GetPtInxFaceSurfaceOnWhichFaceLies: Integer;
    function GetPtInxFaceNextFace: Integer;
    function GetPtInxShellFirstFaceInShell: Integer;
    function GetPtInxShellNextShell: Integer;
    function GetPtInxLumpFirstShellInLump: Integer;
    function GetPtInxLumpNextLump: Integer;
    function GetPtRecInxBeforeDataValues: Integer;
    function GetReversed(const AIndex: Integer;
      const AReversedStr: string = sSatReversed): Integer;
    procedure LoadHeaderFromStrList(const HeaderStrs: TStringList);
    function MakeBody(ARootBrep: TList; AIndex: Integer): Integer;
    function MakeCoEdge(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer): Integer;
    procedure MakeCurve(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
    procedure MakeEdge(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
    function MakeFace(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer): Integer;
    function MakeLoop(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer): Integer;
    function MakeLump(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer): Integer;
    function MakeShell(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer): Integer;
    function MakeSurface(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer): Integer;
    function PrepareForParcing: Boolean;
    function PtRecFindByIndex(const StrIndex, PointerIndex: Integer;
      const SearchingNames: array of string; PosIndex: Integer = 1;
      IsCanInxBeEqual: Boolean = False; IsNeedToCheckDec: Boolean = False): Integer;
    function PtRecPos(const StrIndex, PointerIndex: Integer): Integer;
    function ReadParam(const AStr: string; const APos: Integer;
      var ABytesCopied: Integer): string;
    function ReadParamAsString(const AStr: string; var APos: Integer;
      var AStringValue: string): Integer;
    function ReadParamAsFloat(const AStr: string;
      var APos: Integer; var AFloatValue: Double): Integer;
    function ReadParamAsInteger(const AStr: string;
      var APos: Integer; var AIntValue: Integer): Integer;
    function ReadString(const AStr: string; var APos: Integer): string;
    function ReadInteger(const AStr: string; var APos: Integer): Integer;
    function ReadFloat(const AStr: string; var APos: Integer): Double;
    function ReadFPoint(const AStr: string; var APos: Integer): TFPoint;
    procedure ReadInterval(const AStr: string; var APos: Integer;
       var FRangeaA: Double; var FRangeaB: Double);
    procedure SetCoEdgeReversed(const AEntity: TsgDXFEntity);
    procedure SetStatus(const Value: Boolean);
    function GetSATStringsClear(const AIndex: Integer): string;
  protected
    function GetErrorData: Integer;
    procedure ChangeDelimiter(const ADelimiter: Char);
    function GetInterval(var S: string): string;
    property FileHeader: TsgSATFileHeader read GetFileHeader;
    property SATStrings[const AIndex: Integer]: string read GetSATString;
    property SATStringsClear[const AIndex: Integer]: string read
      GetSATStringsClear;
    property SATStringsCount: Integer read GetSATStringsCount;
    property Status: Boolean read GetStatus write SetStatus;
    property Version: Integer read GetVersion;
  public
    constructor Create(const AConv: TsgDXFConverter);
    destructor Destroy; override;
//    procedure GetMeshBrep(const ADrawWireFunc: TsgCallBackLine;
//      const ADrawISOFunc: TsgCallBackLine; const ADrawTestFunc: TsgCallBackLine;
//      const ATriangleFunc: TsgGetTriangleFunc;
//      const ASelf: Pointer; const AMeshParam: Pointer);
    function Parse(const AEntity: TsgDXFACISEntity): Boolean;
  end;

  procedure CallBackDrawWireVertexDraw(AData: PsgTestLine); cdecl;
  procedure CallBackDrawISOVertexDraw(AData: PsgTestLine); cdecl;
  procedure CallBackDrawTestVertexDraw(AData: PsgTestLine); cdecl;

  procedure GetTriangle(DimTriangle: PsgDimTriangle; Param: Pointer); cdecl;
  procedure BeginSegment(Param: Pointer; IndexFaceMap: Integer;
    SegmentData: PsgSegmentData); cdecl;
  procedure EndSegment(Param: Pointer); cdecl;



var
  GlobalMultithreading: Integer;
{$IFDEF SG_BREP_TOPOLOGY}
  GlobalCalcTopogy: Integer;
{$ENDIF}


implementation

type
  TsgDXFEntityAccess = class(TsgDXFEntity);
  TsgDXFPenLineAccess = class(TsgDXFPenLine);
  TsgDXFEllipseAccess = class(TsgDXFEllipse);
  TsgDXFSplineAccess = class(TsgDXFSpline);
  TsgDXFConverterAccess = class(TsgDXFConverter);
  TsgDXFInsertAccess = class(TsgDXFInsert);
  TsgPolyline3D = class(TsgDXFSpline);//abstract class

function GetAngleParam(const AEllipse: TsgDXFEllipse; const APoint: TFPoint): Double;
begin
  Result := sgFunction.GetAngleParam(AEllipse.Point, AEllipse.RadPt,
    AEllipse.Ratio, APoint);
end;

{ TsgEntityBrep }

function TsgEntityBrepTopology.Add(AType: TsgDXFEntityClass): TsgEntityBrepTopology;
begin
  Result := TsgEntityBrepTopology(AType.Create);
  Result.FOwned := Self;
  FChildren.Add(Result);
end;

constructor TsgEntityBrepTopology.Create;
begin
  inherited Create;
  FChildren := TList.Create;
end;

destructor TsgEntityBrepTopology.Destroy;
begin
  FreeList(FChildren);
  inherited;
end;

function TsgEntityBrepTopology.Owner: TsgEntityBrepTopology;
begin
  Result := FOwned;
end;

{ TsgEntityBrep }

function TsgEntityBrep.GetBrepEntType: TsgBrepEntities;
begin
  Result := seBrepEntity;
end;

{ TsgEntityBrepTwo }

function TsgEntityBrepTwo.AddTwo(AType: TsgDXFEntityClass): TsgEntityBrepTopology;
begin
  Result := TsgEntityBrepTopology(AType.Create);
  FChildrenTwo.Add(Result);
end;

constructor TsgEntityBrepTwo.Create;
begin
  inherited Create;
  FChildrenTwo := TList.Create;
end;

destructor TsgEntityBrepTwo.Destroy;
begin
  FreeList(FChildrenTwo);
  inherited;
end;

{ TsgEntityBrepThree }

function TsgEntityBrepThree.AddThree(AType: TsgDXFEntityClass): TsgEntityBrepTopology;
begin
  Result := TsgEntityBrepTopology(AType.Create);
  FChildrenThree.Add(Result);
end;

constructor TsgEntityBrepThree.Create;
begin
  inherited Create;
  FChildrenThree := TList.Create;
end;

destructor TsgEntityBrepThree.Destroy;
begin
  FreeList(FChildrenThree);
  inherited;
end;

{ TsgEdge }

constructor TsgBrepEdge.Create;
begin
  inherited Create;;
  FCurve := nil;
end;

destructor TsgBrepEdge.Destroy;
begin
  if Assigned(FCurve) then
    FCurve.Free;
  inherited;
end;

function TsgBrepEdge.AddVertice: TsgBrepVertices;
begin
  Result := TsgBrepVertices(Add(TsgBrepVertices));
end;

{ TsgBody }

function TsgBody.AddLump: TsgBrepLump;
begin
  Result := TsgBrepLump(Add(TsgBrepLump));
end;

{ TsgLump }

function TsgBrepLump.AddShell: TsgBrepShell;
begin
  Result := TsgBrepShell(Add(TsgBrepShell));
end;

{ TsgShell }

function TsgBrepShell.AddFace: TsgBrepFace;
begin
  Result := TsgBrepFace(Add(TsgBrepFace));
end;

function TsgBrepShell.AddSubShell: TsgBrepSubShell;
begin
  Result := TsgBrepSubShell(AddThree(TsgBrepSubShell));
end;

function TsgBrepShell.AddWire: TsgBrepWire;
begin
  Result := TsgBrepWire(AddTwo(TsgBrepWire));
end;

{ TsgFace }

constructor TsgBrepFace.Create;
begin
  inherited Create;
  ZeroMemory(@FContext, SizeOf(FContext));
end;

destructor TsgBrepFace.Destroy;
begin
  if FContext.Context <> nil then
    sgFreeContext(@FContext);
  if Assigned(FSufface) then
    FSufface.Free;
  inherited Destroy;
end;

function TsgBrepFace.AddLoop: TsgBrepLoop;
begin
  Result := TsgBrepLoop(Add(TsgBrepLoop));
end;

function TsgBrepFace.GetContex: PsgContext;
begin
  Result := @FContext;
end;

{ TsgLoop }

function TsgBrepLoop.AddCoEdge: TsgBrepCoEdge;
begin
  Result := TsgBrepCoEdge(Add(TsgBrepCoEdge));
end;

{ TsgCoEdge }

function TsgBrepCoEdge.AddEdge: TsgBrepEdge;
begin
  Result := TsgBrepEdge(Add(TsgBrepEdge));
end;

{ TsgBrepConeSurface }

constructor TsgBrepConeSurface.Create;
begin
  inherited Create;
  FBase := TsgBrepEllipsCurve.Create;
end;

destructor TsgBrepConeSurface.Destroy;
begin
  FBase.Free;
  inherited;
end;

function TsgBrepConeSurface.GetBrepEntType: TsgBrepEntities;
begin
  Result := seConeSurface;
end;

{ TsgBrepSphereSurface }

function TsgBrepSphereSurface.GetBrepEntType: TsgBrepEntities;
begin
  Result := seSphereSurface;
end;

{ TsgBrepTorusSurface }

function TsgBrepTorusSurface.GetBrepEntType: TsgBrepEntities;
begin
  Result := seTorusSurface;
end;

{ TsgBrepBs3Curve }

constructor TsgBrepBs3Curve.Create;
begin
  inherited Create;
  FControlPoints := TFPointList.Create;
  FKnots := TsgDoubleList.Create;
  FMultiplicities := TsgIntegerList.Create;
  FWeights := TsgDoubleList.Create;
end;

destructor TsgBrepBs3Curve.Destroy;
begin
  FControlPoints.Free;
  FKnots.Free;
  FMultiplicities.Free;
  FWeights.Free;
  inherited;
end;

function TsgBrepBs3Curve.GetBrepEntType: TsgBrepEntities;
begin
  Result := seBs3Curve;
end;

{ TsgBrepExactCurve }

constructor TsgBrepExactCurve.Create;
begin
  inherited Create;
  FBs3Curve := TsgBrepBs3Curve.Create;
end;

destructor TsgBrepExactCurve.Destroy;
begin
  FBs3Curve.Free;
  inherited;
end;

function TsgBrepExactCurve.GetBrepEntType: TsgBrepEntities;
begin
  Result := seExactCurve;
end;

{ TsgBrepIntCurve }

constructor TsgBrepIntCurve.Create;
begin
  inherited Create;
end;

destructor TsgBrepIntCurve.Destroy;
begin
  inherited;
end;


{ TsgBrepBs3Surface }

constructor TsgBrepBs3Surface.Create;
begin
  inherited Create;
  FControlPoints := TFPointList.Create;
  FKnots := TsgDoubleList.Create;
  FMultiplicities := TsgIntegerList.Create;
  FWeights := TsgDoubleList.Create;
end;

destructor TsgBrepBs3Surface.Destroy;
begin
  FControlPoints.Free;
  FKnots.Free;
  FMultiplicities.Free;
  FWeights.Free;
  inherited;
end;

{ TsgBrepExactSplineSurface }

constructor TsgBrepExactSplineSurface.Create;
begin
  inherited Create;
  FBs3SurfaceU := TsgBrepBs3Surface.Create;
  FBs3SurfaceV := TsgBrepBs3Surface.Create;
  FControlPointsUV := TFPointList.Create;
  FWeightsUV := TsgDoubleList.Create;
end;

destructor TsgBrepExactSplineSurface.Destroy;
begin
  FControlPointsUV.Free;
  FWeightsUV.Free;
  FBs3SurfaceU.Free;
  FBs3SurfaceV.Free;
  inherited;
end;

function TsgBrepExactSplineSurface.GetBrepEntType: TsgBrepEntities;
begin
  Result := seExactSplineSurface;
end;

{ TsgBrepEntity }

function TsgBrepEntityGeometry.GetBrepEntType: TsgBrepEntities;
begin
  Result := seBrepEntity;
end;

{ TsgBrepPlaneSurface }

function TsgBrepPlaneSurface.GetBrepEntType: TsgBrepEntities;
begin
  Result := sePlaneSurface;
end;

{ TsgBrepEllipsCurve }

function TsgBrepEllipsCurve.GetBrepEntType: TsgBrepEntities;
begin
  Result := seEllipsCurve;
end;

{ TsgBrepStraightCurve }

function TsgBrepStraightCurve.GetBrepEntType: TsgBrepEntities;
begin
  Result := seStraightCurve;
end;

{ TsgBrepHelixCurve }

function TsgBrepHelixCurve.GetBrepEntType: TsgBrepEntities;
begin
  Result := seHelixCurve;
end;

  {TsgSATParser}

procedure TsgSATParser.ChangeDelimiter(const ADelimiter: Char);
{$IFDEF SGDEL_2006}
begin
  FSATStrings.Text := SysUtils.StringReplace(FSATStrings.Text, FDelimiter,
    ADelimiter, [rfReplaceAll, rfIgnoreCase]);
  FDelimiter := ADelimiter;
end;
{$ELSE}
var
  S: string;
begin
  S := FSATStrings.Text;
  ReplaceToPos(S, FDelimiter, ADelimiter, Length(S));
  FSATStrings.Text := S;
  FDelimiter := ADelimiter;
end;
{$ENDIF}

procedure TsgSATParser.CheckIncorrectAttribs;
//var
//  I: Integer;
//  vStr: string;
begin
//  I := 0;
//  while I < SATStringsCount - 1 do
//  begin
//    vStr := FSATStrings[I];
//    if (AnsiPos(sSatDXIDattrib1, vStr) > 0) or
//       (AnsiPos(sSatDXIDattrib2, vStr) > 0) then
//    begin
//      FSATStrings[I] := vStr + FSATStrings[I + 1];
//      FSATStrings.Delete(I + 1);
//    end;
//    Inc(I);
//  end;
end;

function TsgSATParser.CheckIndex(const Index: Integer): Integer;
begin
  Result := Index;
  if (Result > 1) and (Version < cntSatDefVersion) then
    Dec(Result);
end;

function TsgSATParser.CheckSatName(const Index: Integer;
  const Names: array of string): Integer;
var
  I: Integer;
  vName: string;
  vResult: Boolean;
begin
  Result := Index;
  vResult := False;
  vName := GetNameValueOfString(Index);
  for I := Low(Names) to High(Names) do
    if vName = Names[I] then
    begin
      vResult := True;
      Break;
    end;
  Status := vResult;
end;


function TsgSATParser.GetSATString(const AIndex: Integer): string;
begin
  Result := '';
  if (AIndex >= 0) and (AIndex < FSATStrings.Count) then
  begin
    Result := FSATStrings[AIndex];
    ReplaceToPos(Result, #9, '', Length(Result));
  end
  else
    GetErrorData;
end;

function TsgSATParser.GetSATStringsClear(const AIndex: Integer): string;
var
  vStatus: Boolean;
begin
  vStatus := Status;
  try
    Result := SATStrings[AIndex];
  finally
    Status := vStatus;
  end;
  if (Result <> '') and (FDelimiter <> ' ') then
    ReplaceToPos(Result, FDelimiter, ' ', Length(Result));
end;

function TsgSATParser.GetSATStringsCount: Integer;
begin
  Result := FSATStrings.Count;
end;

function TsgSATParser.GetStatus: Boolean;
begin
  Result := FParsingStatus;
end;

function TsgSATParser.GetStrWithDataValues(const StrIndex,
  PtRecInxBeforeDataValues: Integer): string;
var
  vStr: string;
  vPos: Integer;
begin
  Result := '';
  vStr := SATStrings[StrIndex];
  if Status and (Length(vStr) > 0) then
  begin
    vPos := PtRecPos(StrIndex, PtRecInxBeforeDataValues);
    if vPos > 0 then
    begin
      vPos := StringPos(FDelimiter, vStr, vPos);
      if vPos > 0 then
        Result := Copy(vStr, vPos + Length(FDelimiter), MaxInt)
      else
        Status := False;
    end
    else
      Status := False;
  end;
end;

constructor TsgSATParser.Create(const AConv: TsgDXFConverter);
begin
  inherited Create;
  FConverter := AConv;
  FSATStrings := TStringList.Create;
  FDelimiter := sSatDelimiter0;
  FEofStr := sSatEofStr;
  FHeader.Version := cntSatDefVersion;
  FHeader.TotalNumRecords := 0;
  FHeader.CountNumOfEnt := 0;
  FHeader.LeastSignBit := 0;
  FHeader.FileProducerInfo := '';
  FHeader.MillimetersByEachUnit := 1;
  FHeader.Resabs := 0;
  FHeader.Resnor := 0;
  FBodiesIndexes := TsgIntegerList.Create;
  FBodiesIndexes.Sorted := False;
  FNeedToDec := False;
end;

procedure TsgSATParser.AddEntity(const AEntity: TsgDXFEntity);
begin
  if Assigned(FSatCreateEntity) then
    FSatCreateEntity.AddEntity(AEntity);
end;

function TsgSATParser.CreateEntity(const AClass: TClass): TsgDXFEntity;
var
  vIsCreated: Boolean;
begin
  Result := nil;
  if Assigned(FSatCreateEntity) then
    Result := FSatCreateEntity.CreateEntity(AClass, nil, nil, vIsCreated);
end;

procedure TsgSATParser.SetCoEdgeReversed(const AEntity: TsgDXFEntity);
var
  vPoly: TsgCADBasePolyline;
  vPoint, vPoint1: TFPoint;
begin
  if FCoEdgeReversed and (not IsLoadMeshBuilderDll) then
    case AEntity.EntType of
      ceLine:
        begin
          vPoint := TsgDXFLine(AEntity).Point;
          vPoint1 := TsgDXFLine(AEntity).Point1;
          TsgDXFLine(AEntity).Point := vPoint1;
          TsgDXFLine(AEntity).Point1 := vPoint;
        end;
      ceEllipse, ceSpline:
        begin
          vPoly := TsgCADBasePolyline(AEntity);
          vPoly.Flags := vPoly.Flags or 8;
        end;
    end;
end;

procedure TsgSATParser.SetStatus(const Value: Boolean);
begin
  if Value <> FParsingStatus then
    FParsingStatus := Value;
end;

function TsgSATParser.ReadParam(const AStr: string; const APos: Integer;
  var ABytesCopied: Integer): string;
var
  vPos: Integer;
begin
  vPos := StringScan(FDelimiter, AStr, APos);
  if vPos > 0 then
  begin
    ABytesCopied := vPos - APos;
    Result := Copy(AStr, APos, ABytesCopied);
    Inc(ABytesCopied);
  end
  else
  begin
    Result := '';
    ABytesCopied := 0;
  end;
end;

function TsgSATParser.ReadFloat(const AStr: string; var APos: Integer): Double;
begin
  ReadParamAsFloat(AStr, APos, Result);
end;

function TsgSATParser.ReadInteger(const AStr: string; var APos: Integer): Integer;
begin
  ReadParamAsInteger(AStr, APos, Result);
end;

function TsgSATParser.ReadString(const AStr: string; var APos: Integer): string;
begin
  ReadParamAsString(AStr, APos, Result);
end;

procedure TsgSATParser.ReadInterval(const AStr: string; var APos: Integer;
  var FRangeaA: Double; var FRangeaB: Double);
begin
  if ReadString(AStr, APos) = 'F' then
    FRangeaA := ReadFloat(AStr, APos)
  else
    FRangeaA := MinDouble;
  if ReadString(AStr, APos) = 'F' then
    FRangeaB := ReadFloat(AStr, APos)
  else
    FRangeaB := MaxDouble;
end;

function TsgSATParser.ReadParamAsString(const AStr: string; var APos: Integer;
  var AStringValue: string): Integer;
var
  vStrPar: string;
  vBytesCopied: Integer;
begin
  Result := -1;
  vStrPar := ReadParam(AStr, APos, vBytesCopied);
  if vBytesCopied > 0 then
  begin
    Inc(APos, vBytesCopied);
    AStringValue := vStrPar;
    Result := 1;
  end
  else
    AStringValue := '';
end;

function TsgSATParser.ReadParamAsFloat(const AStr: string; var APos: Integer;
  var AFloatValue: Double): Integer;
var
  vStrPar: string;
  vCode, vBytesCopied: Integer;
begin
  Result := -1;
  vStrPar := ReadParam(AStr, APos, vBytesCopied);
  if vBytesCopied > 0 then
  begin
    Inc(APos, vBytesCopied);
    Val(vStrPar, AFloatValue, vCode);
    Result := Integer((vCode = 0) and (vStrPar <> ''));
  end;
end;

function TsgSATParser.ReadParamAsInteger(const AStr: string; var APos,
  AIntValue: Integer): Integer;
var
  vStrPar: string;
  vCode, vBytesCopied: Integer;
begin
  Result := -1;
  vStrPar := ReadParam(AStr, APos, vBytesCopied);
  if vBytesCopied > 0 then
  begin
    Inc(APos, vBytesCopied);
    Val(vStrPar, AIntValue, vCode);
    Result := Integer((vCode = 0) and (vStrPar <> ''));
  end;
end;

procedure TsgSATParser.DecodeProprietaryData;
var
  vProprietaryData, vCurrentData: string;
  Ch, PrevCh: Char;
  I, J: Integer;
begin
  if not FACIS.ProprietaryDataDecoded then
  begin
    PrevCh := #0;
    vProprietaryData := '';
    for I := 0 to FACIS.ProprietaryData.Count -1 do
    begin
      vCurrentData := FACIS.ProprietaryData[I];
      for J := 1 to Length(vCurrentData) do
      begin
        Ch := Chr(Byte(vCurrentData[J]));
        if PrevCh = #$41 then
        begin
          PrevCh := Ch;
          Continue;
        end;
        if Ch = #$20 then
          PrevCh := Ch
        else
          PrevCh := Chr(Byte(159 - Byte(Ch)));
        vProprietaryData := vProprietaryData + PrevCh;
      end;
      PrevCh := #0;
      vProprietaryData := vProprietaryData + #13#10;
    end;

    FSATStrings.Text := vProprietaryData;
  end
  else
    FSATStrings.Assign(FACIS.ProprietaryData);
  if not FACIS.IncorrectAttribsChecked then
    CheckIncorrectAttribs;
end;

destructor TsgSATParser.Destroy;
begin
  FSATStrings.Free;
  FBodiesIndexes.Free;
  FHeader.FileProducerInfo := '';
  inherited Destroy;
end;

function TsgSATParser.PtRecFindByIndex(const StrIndex, PointerIndex: Integer;
  const SearchingNames: array of string; PosIndex: Integer = 1;
  IsCanInxBeEqual: Boolean = False; IsNeedToCheckDec: Boolean = False): Integer;
var
  S: string;
//  vNeedToDec: Boolean;

  function IsNeedToDec(const Index: Integer): Boolean;
  var
    S, vSearchingName: string;
    I, vNeedToDecCount: Integer;
    vNeedToDec: Boolean;
  begin
    vNeedToDecCount := -1;
    if Status and (Index > 0) then
    begin
      for I := Low(SearchingNames) to High(SearchingNames) do
      begin
        S := GetNameValueOfString(Index);
        vSearchingName := SearchingNames[I];
        if PosIndex = 1 then
          vNeedToDec := S <> vSearchingName
        else
          vNeedToDec := (Pos(vSearchingName, S) > 0) ;
        if vNeedToDec then
          Inc(vNeedToDecCount);
      end;
    end;
    Result := (vNeedToDecCount > -1) and (vNeedToDecCount = High(SearchingNames));
  end;

begin
  S := SATStrings[StrIndex];
  Result := StringPosNum(sSatRecNumPtr, S, PointerIndex, 1);
  if Result = 0 then
    Status := False
  else
  begin
    S := Copy(S, Result + 1, MaxInt);
    Result := Pos(FDelimiter, S);
    if Result = 0 then
      Result := Pos(FEofStr, S);
    if Result <> 0 then
    begin
      S := Copy(S, 1, Result - 1);
      Result := StrToIntDef(S, 0);
    end;
  end;
  if IsNeedToCheckDec then
    FNeedToDec := IsNeedToDec(Result);
  if FNeedToDec then
    Dec(Result);
  if (Result = StrIndex) and (not IsCanInxBeEqual) then
  begin
    Status := False;
    Result := -1;
  end;
//  if Result = 0 then
//    Status := False
//  else
//    Status := True;
end;




function TsgSATParser.ReadFPoint(const AStr: string; var APos: Integer): TFPoint;
begin
  repeat
  until ReadParamAsFloat(AStr, APos, Result.X) <> 0;
  ReadParamAsFloat(AStr, APos, Result.Y);
  ReadParamAsFloat(AStr, APos, Result.Z);
end;

procedure TsgSATParser.AddStraightCurve(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
var
  vLine: TsgDXFLine;
  vStraightSat: TsgBrepStraightCurve;
  vTmpStr: string;
  vPos: Integer;
  vRangeaA, vRangeaB: Double;
begin
  vTmpStr := GetStrWithDataValues(AIndex, GetPtRecInxBeforeDataValues);
  vPos := 1;
  vStraightSat := TsgBrepStraightCurve.Create;
{$IFDEF SG_BREP_DEBUG}
  vStraightSat.FIndex := AIndex;
{$ENDIF}
  vStraightSat.FRoot := ReadFPoint(vTmpStr, vPos);
  vStraightSat.FDirection := ReadFPoint(vTmpStr, vPos);
  ReadInterval(vTmpStr, vPos, vRangeaA, vRangeaB);
  vStraightSat.RangeaA := vRangeaA;
  vStraightSat.RangeaB := vRangeaB;
  if not AddBrepLink(ABrepEntity, vStraightSat) then
    vStraightSat.Free;
  //
  if not IsLoadMeshBuilderDll  then
  begin
    vLine := TsgDXFLine(CreateEntity(TsgDXFLine));
    vLine.Point := FPoints[0];
    vLine.Point1 := FPoints[1];
    AddEntity(vLine);
  end;
end;

procedure TsgSATParser.AddHelixCurve(ABrepEntity: TsgEntityBrepTopology;
  AIndex: Integer);
begin
  FBadSurface := True;
end;

procedure TsgSATParser.AddPlanSurface(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
var
  vSurfaceSat: TsgBrepPlaneSurface;
  vTmpStr: string;
  vPos: Integer;
begin
  vTmpStr := GetStrWithDataValues(AIndex, GetPtRecInxBeforeDataValues);
  vPos := 1;
  vSurfaceSat := TsgBrepPlaneSurface.Create;
  vSurfaceSat.RootPoint := ReadFPoint(vTmpStr, vPos);
  vSurfaceSat.Normal := ReadFPoint(vTmpStr, vPos);
  vSurfaceSat.UDeriv := ReadFPoint(vTmpStr, vPos);
  vSurfaceSat.ReverseV := GetReversed(AIndex, sSatReverse_v) > 0;
  if not AddBrepLink(ABrepEntity, vSurfaceSat) then
    vSurfaceSat.Free;
end;

procedure TsgSATParser.AddSphereSurface(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
var
  vSurfaceSat: TsgBrepSphereSurface;
  vTmpStr: string;
  vPos: Integer;
begin
  vTmpStr := GetStrWithDataValues(AIndex, GetPtRecInxBeforeDataValues);
  vPos := 1;
  vSurfaceSat := TsgBrepSphereSurface.Create;
  vSurfaceSat.Center := ReadFPoint(vTmpStr, vPos);
  vSurfaceSat.Radius := ReadFloat(vTmpStr, vPos);
  vSurfaceSat.UVOridir := ReadFPoint(vTmpStr, vPos);
  vSurfaceSat.PoleDir := ReadFPoint(vTmpStr, vPos);
  vSurfaceSat.ReverseV := GetReversed(AIndex, sSatReverse_v) > 0;
  if not AddBrepLink(ABrepEntity, vSurfaceSat) then
    vSurfaceSat.Free;
end;

procedure TsgSATParser.AddSplineSurface(ABrepEntity: TsgEntityBrepTopology;
  AIndex: Integer);
var
  vSurfaceSat: TsgBrepExactSplineSurface;
  vContentDataStr, vTypeSurface: string;
  vIdentType, vSaveApproxLevell, IdentRational: string;
  I, vPos, vCountControlPointU, vCountControlPointV: Integer;
//  vFlag: Boolean;
//  vTempStringList: TsgStringList;
begin

  vContentDataStr := GetContentData(AIndex);
  vTypeSurface := GetSubString(vContentDataStr, 1);
  if vTypeSurface = sSatSweepsur then
  begin
    Exit; // No suport

//    vContentDataStr := StringTrim(FSATStrings[AIndex], sSatSubtypeStart, sSatSubtypeEnd);  GetContentData(AIndex);
//
//    I := 0;
//    vFlag := False;
//    while I <= Length(vContentDataStr) do
//    begin
//      if vContentDataStr[I] = sSatSubtypeStart then
//        vFlag := True;
//      if vContentDataStr[I] = sSatSubtypeEnd then
//        vFlag := False;
//      if vFlag  and (vContentDataStr[I] = #9) then
//        vContentDataStr[I] := ' ';
//      Inc(I);
//    end;
//
//    vTempStringList := TsgStringList.Create;
//    try
//      vTempStringList.LineBreak := #9;
//      vTempStringList.Text := vContentDataStr;
//      vContentDataStr := ' sweepsur ';
//      for I := 25 to vTempStringList.Count -1 do
//      begin
//        vContentDataStr := vContentDataStr + ' ' + vTempStringList[I]
//      end;
//      while ReplaceToPos(vContentDataStr, ' ' + ' ', ' ', Length(vContentDataStr)) > 0 do;
//    finally
//      vTempStringList.Free;
//    end;
  end;

  if IndexOfStrings(vTypeSurface, sSatTypeSplineSurface) <> -1 then
  begin
    vSurfaceSat := TsgBrepExactSplineSurface.Create;
    if (vTypeSurface <> sSatExactsur) or (FHeader.VersionOriginal > 300) or
      (TsgDWGVersion(FConverter.HeadVarStruct.Version) >= acR2004) then
    begin
      vSaveApproxLevell := GetSubString(vContentDataStr, 2);
      vIdentType := GetSubString(vContentDataStr, 3);
    end
    else
      vIdentType := GetSubString(vContentDataStr, 2);
    vPos := GetPosNext(vIdentType, vContentDataStr)+1;
    vSurfaceSat.Bs3SurfaceU.Degree := ReadInteger(vContentDataStr, vPos);
    vSurfaceSat.Bs3SurfaceV.Degree := ReadInteger(vContentDataStr, vPos);
    if (vIdentType = sSatNurbs) then
    begin
      IdentRational := ReadString(vContentDataStr, vPos);
      vSurfaceSat.Bs3SurfaceU.IdentClosere :=
        IndexOfStrings(ReadString(vContentDataStr, vPos), sSatIdentClosureSurface);
      vSurfaceSat.Bs3SurfaceV.IdentClosere :=
        IndexOfStrings(ReadString(vContentDataStr, vPos), sSatIdentClosureSurface);
      vSurfaceSat.Bs3SurfaceU.IdentSingularities :=
        IndexOfStrings(ReadString(vContentDataStr, vPos), sSatIdentSingularities);
      vSurfaceSat.Bs3SurfaceV.IdentSingularities :=
        IndexOfStrings(ReadString(vContentDataStr, vPos), sSatIdentSingularities);
    end;
    if (vIdentType = sSatNubs) then
    begin
      vSurfaceSat.Bs3SurfaceU.IdentClosere :=
        IndexOfStrings(ReadString(vContentDataStr, vPos), sSatIdentClosureSurface);
      vSurfaceSat.Bs3SurfaceV.IdentClosere :=
        IndexOfStrings(ReadString(vContentDataStr, vPos), sSatIdentClosureSurface);
      vSurfaceSat.Bs3SurfaceU.IdentSingularities :=
        IndexOfStrings(ReadString(vContentDataStr, vPos), sSatIdentSingularities);
      vSurfaceSat.Bs3SurfaceV.IdentSingularities :=
        IndexOfStrings(ReadString(vContentDataStr, vPos), sSatIdentSingularities);
    end;
    vSurfaceSat.Bs3SurfaceU.Knots.Count := ReadInteger(vContentDataStr, vPos);
    vSurfaceSat.Bs3SurfaceV.Knots.Count := ReadInteger(vContentDataStr, vPos);
    vCountControlPointU := 0;
    for I := 0 to vSurfaceSat.Bs3SurfaceU.Knots.Count-1 do
    begin
      vSurfaceSat.Bs3SurfaceU.Knots[I] := ReadFloat(vContentDataStr, vPos);
      vSurfaceSat.Bs3SurfaceU.Multiplicities.Add(ReadInteger(vContentDataStr, vPos));
      Inc(vCountControlPointU, vSurfaceSat.Bs3SurfaceU.Multiplicities[I]);
    end;
    vCountControlPointV := 0;
    for I := 0 to vSurfaceSat.Bs3SurfaceV.Knots.Count-1 do
    begin
      vSurfaceSat.Bs3SurfaceV.Knots[I] := ReadFloat(vContentDataStr, vPos);
      vSurfaceSat.Bs3SurfaceV.Multiplicities.Add(ReadInteger(vContentDataStr, vPos));
      Inc(vCountControlPointV, vSurfaceSat.Bs3SurfaceV.Multiplicities[I]);
    end;
    vSurfaceSat.Bs3SurfaceU.ControlPoints.Count :=
      vCountControlPointU + 1 - vSurfaceSat.Bs3SurfaceU.Degree;
    vSurfaceSat.Bs3SurfaceV.ControlPoints.Count :=
      vCountControlPointV + 1 - vSurfaceSat.Bs3SurfaceV.Degree;

    vSurfaceSat.ControlPointsUV.Count :=
      vSurfaceSat.Bs3SurfaceU.ControlPoints.Count*vSurfaceSat.Bs3SurfaceV.ControlPoints.Count;
    for I := 0 to vSurfaceSat.ControlPointsUV.Count -1 do
    begin
      vSurfaceSat.ControlPointsUV[I] := ReadFPoint(vContentDataStr, vPos);
      if vIdentType = sSatNurbs then
        vSurfaceSat.WeightsUV.Add(ReadFloat(vContentDataStr, vPos));
    end;
    if not AddBrepLink(ABrepEntity, vSurfaceSat) then
      vSurfaceSat.Free;
  end;
end;

procedure TsgSATParser.AddTorusSurface(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
var
  vSurfaceSat: TsgBrepTorusSurface;
  vTmpStr: string;
  vPos: Integer;
begin
  vTmpStr := GetStrWithDataValues(AIndex, GetPtRecInxBeforeDataValues);//CopyFromStr(AIndex, 1);
  vPos := 1;
  vSurfaceSat := TsgBrepTorusSurface.Create;
  vSurfaceSat.Center := ReadFPoint(vTmpStr, vPos);
  vSurfaceSat.Normal := ReadFPoint(vTmpStr, vPos);
  vSurfaceSat.MajorRadius := ReadFloat(vTmpStr, vPos);
  vSurfaceSat.MinorRadius := ReadFloat(vTmpStr, vPos);
  vSurfaceSat.UVOridir := ReadFPoint(vTmpStr, vPos);
  vSurfaceSat.ReverseV := GetReversed(AIndex, sSatReverse_v) > 0;
  if not AddBrepLink(ABrepEntity, vSurfaceSat) then
    vSurfaceSat.Free;
end;

procedure TsgSATParser.AddConeSurface(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
var
  vSurfaceSat: TsgBrepConeSurface;
  vTmpStr: string;
  vPos: Integer;
  vRangeaA, vRangeaB: Double;
begin
  vTmpStr := GetStrWithDataValues(AIndex, GetPtRecInxBeforeDataValues);
  vPos := 1;
  vSurfaceSat := TsgBrepConeSurface.Create;
  vSurfaceSat.Base.Center := ReadFPoint(vTmpStr, vPos);
  vSurfaceSat.Base.Normal := ReadFPoint(vTmpStr, vPos);
  vSurfaceSat.Base.MajorAxis := ReadFPoint(vTmpStr, vPos);
  vSurfaceSat.Base.RadiusRatio := ReadFloat(vTmpStr, vPos);
  ReadInterval(vTmpStr, vPos, vRangeaA, vRangeaB);
  vSurfaceSat.Base.RangeaA := vRangeaA;
  vSurfaceSat.Base.RangeaB := vRangeaB;
  vSurfaceSat.SineAngle := ReadFloat(vTmpStr, vPos);
  vSurfaceSat.CosineAngle := ReadFloat(vTmpStr, vPos);
  vSurfaceSat.UParamScale := ReadFloat(vTmpStr, vPos);
  vSurfaceSat.ReverseU := GetReversed(AIndex) > 0;
  if not AddBrepLink(ABrepEntity, vSurfaceSat) then
    vSurfaceSat.Free;
end;

function TsgSATParser.AddBrepLink(ABrepEntity: TsgEntityBrepTopology;
  ASurface: TsgBrepSurface): Boolean;
begin
  Result := False;
  if ABrepEntity is TsgBrepFace then
  begin
    TsgBrepFace(ABrepEntity).Sufface := ASurface;
    Result := True;
  end;
end;

function TsgSATParser.AddBrepLink(ABrepEntity: TsgEntityBrepTopology;
      ACurve: TsgBrepCurve): Boolean;
begin
  Result := False;
  if ABrepEntity is TsgBrepEdge then
  begin
    TsgBrepEdge(ABrepEntity).Curve := ACurve;
    Result := True;
  end;
end;

procedure TsgSATParser.AddEllipseCurve(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
var
  vElliptic: TsgDXFEllipse;
  vTmpStr: string;
  vEllipticStartPt, vEllipticEndPt, vExtrusion: TFPoint;
  vPos: Integer;
  vD, vRangeaA , vRangeaB: Double;
  vEllipseSat: TsgBrepEllipsCurve;
  vAddEllipse: Boolean;

  function GetDoPreExtrudedPoint(const P, N: TFPoint): TFPoint;
  begin
    Result := P;
    DoPreExtrusion(Result, N);
  end;

begin
  vEllipticStartPt := FPoints[0];
  vEllipticEndPt := FPoints[1];
  vTmpStr := GetStrWithDataValues(AIndex, GetPtRecInxBeforeDataValues);//CopyFromStr(AIndex, 1);
  vPos := 1;
  //
  vEllipseSat := TsgBrepEllipsCurve.Create;
{$IFDEF SG_BREP_DEBUG}
  vEllipseSat.FIndex := AIndex;
{$ENDIF}
  vEllipseSat.Center := ReadFPoint(vTmpStr, vPos);
  vEllipseSat.Normal := ReadFPoint(vTmpStr, vPos);
  vEllipseSat.FMajorAxis := ReadFPoint(vTmpStr, vPos);
  repeat
  until ReadParamAsFloat(vTmpStr, vPos, vD) <> 0;
  vEllipseSat.FRadiusRatio := vD;

  ReadInterval(vTmpStr, vPos, vRangeaA , vRangeaB);

  vEllipseSat.RangeaA := vRangeaA;
  vEllipseSat.RangeaB := vRangeaB;

  vAddEllipse := AddBrepLink(ABrepEntity, vEllipseSat);
  //
  if not IsLoadMeshBuilderDll  then
  begin
    vElliptic := TsgDXFEllipse(CreateEntity(TsgDXFEllipse));
    vElliptic.Point := vEllipseSat.Center;
    TsgDXFEllipseAccess(vElliptic).SetExtrusion(vEllipseSat.Normal);
    vElliptic.RadPt := vEllipseSat.FMajorAxis;
    vElliptic.Ratio := vEllipseSat.FRadiusRatio;
    if TsgDXFEllipseAccess(vElliptic).IsExtruded then
    begin
      vExtrusion := TsgDXFEllipseAccess(vElliptic).GetExtrusion;
      vElliptic.RadPt := GetDoPreExtrudedPoint(vElliptic.RadPt, vExtrusion);
      vElliptic.Point := GetDoPreExtrudedPoint(vElliptic.Point, vExtrusion);
      DoPreExtrusion(vEllipticStartPt, vExtrusion);
      DoPreExtrusion(vEllipticEndPt, vExtrusion);
    end;
    vElliptic.StartAngle := GetAngleParam(vElliptic, vEllipticStartPt);
    vElliptic.EndAngle := GetAngleParam(vElliptic, vEllipticEndPt);
    //evg: the following code is buben dancing but it works to correct the arcs
    {if (vElliptic.EndAngle > 180.01) and  (vElliptic.StartAngle < 179.9) and
      (not FACIS.SATDirect) and (FACIS.Converter <> nil) and (TsgDWGVersion(FACIS.Converter.HeadVarStruct.Version) > acR2000) then //#SDS not sure about this line
    begin
      vD := vElliptic.EndAngle;
      vElliptic.EndAngle := vElliptic.StartAngle;
      vElliptic.StartAngle := vD;
    end;}
    if vElliptic.EndAngle <= vElliptic.StartAngle then
       vElliptic.EndAngle := vElliptic.EndAngle + 360;
    TsgDXFEllipseAccess(vElliptic).FIsExtruded := False;
    AddEntity(vElliptic);
  end;
  if not vAddEllipse then
    vEllipseSat.Free;
end;

procedure TsgSATParser.AddIntCurve(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
var
  vPos, vPos0, vCount, vCount0, J, vKnotCount, vKnotParamsCount, vControlCount: Integer;
  vReadWeight: Byte;
  vNubs, vNurbs, vOpen, vClose, vPeriodic: Integer;
  vTmpStr, vTmpLine: string;
  vSpline: TsgDXFSpline;
  vIsBldcur(*, vIsParCur, vIsExactcur*): Boolean;
  vKnotValue, vValue: Double;
  vControl: TFPoint;
  vDegree: Integer;

  vExactCurve: TsgBrepExactCurve;
  vTypeCurve, vSaveApproxLevell, vIdentType: string;
  I: Integer;
  vIsNumber: Integer;
//  vFitTolerance: Double;

  function ReadValue(var AValue: TsgFloat): Boolean;
  var
    vParam: string;
    vCode, vLength: Integer;
  begin
    repeat
      vParam := ReadParam(vTmpStr, vPos, vLength);
      Inc(vPos, vLength);
    until (vLength > 1) or (vPos >= Length(vTmpStr));
    AValue := StrToVal(vParam, vCode);
    Result := vCode = 0;
  end;

  function ValNoWarnig(const AString: string; var ACode: Integer): Extended;
  begin
    Val(AString, Result, ACode);
  end;

begin
  vTmpLine := GetContentData(AIndex);

  if IsLoadMeshBuilderDll then
  begin
    if (vTmpLine <> '') and (FDelimiter <> ' ') then
      ReplaceToPos(vTmpLine, FDelimiter+FDelimiter, FDelimiter, Length(vTmpLine));
  end;

  vTypeCurve := GetSubString(vTmpLine, 1);

  if IsLoadMeshBuilderDll then
  begin
    if IndexOfStrings(vTypeCurve, sSatTypeIntCur) <> -1 then
    begin
      //
      vExactCurve := TsgBrepExactCurve.Create;
    {$IFDEF SG_BREP_DEBUG}
      vExactCurve.FIndex := AIndex;
    {$ENDIF}
      vSaveApproxLevell := GetSubString(vTmpLine, 2);
      if IndexOfStrings(vSaveApproxLevell, sSatIdentType) <> -1 then
      begin
        vIdentType := vSaveApproxLevell;
      end
      else
      begin
        ValNoWarnig(vSaveApproxLevell, vIsNumber);
        if vIsNumber = 0 then
          vIdentType := GetSubString(vTmpLine, 4)
        else
          vIdentType := GetSubString(vTmpLine, 3);
      end;
      vPos := GetPosNext(vIdentType, vTmpLine)+1;
      vExactCurve.Bs3Curve.Degree := ReadInteger(vTmpLine, vPos);
      vExactCurve.FBs3Curve.IdentClosere := IndexOfStrings(ReadString(vTmpLine, vPos), sSatIdentClosureCurve);
      vExactCurve.Bs3Curve.Knots.Count := ReadInteger(vTmpLine, vPos);
      vControlCount := 0;
      for I := 0 to vExactCurve.Bs3Curve.Knots.Count-1 do
      begin
        vExactCurve.Bs3Curve.Knots[I] := ReadFloat(vTmpLine, vPos);
        vExactCurve.Bs3Curve.Multiplicities.Add(ReadInteger(vTmpLine, vPos));
        Inc(vControlCount, vExactCurve.Bs3Curve.Multiplicities[I]);
      end;
      vExactCurve.Bs3Curve.ControlPoints.Count :=
        vControlCount + 1 - vExactCurve.Bs3Curve.Degree;
      for I := 0 to vExactCurve.Bs3Curve.ControlPoints.Count-1 do
      begin
        vExactCurve.Bs3Curve.ControlPoints[I] := ReadFPoint(vTmpLine, vPos);
        if vIdentType = sSatNurbs then
          vExactCurve.Bs3Curve.Weights.Add(ReadFloat(vTmpLine, vPos));
      end;
      ReadFloat(vTmpLine, vPos);//vFitTolerance :=  ReadFloat(vTmpLine, vPos);
      //First surface for curve definition
      ReadString(vTmpLine, vPos);
      //Second surface for curve definition
      ReadString(vTmpLine, vPos);
      //Parameter space curve on second surface
      ReadString(vTmpLine, vPos);
      //Parameter space curve on second surface
      ReadString(vTmpLine, vPos);
      if not AddBrepLink(ABrepEntity, vExactCurve) then
        vExactCurve.Free;
    end;
    Exit;
  end;

  FBadSurface := True;
  if not IsLoadMeshBuilderDll then
  begin
    // Draw no support OpenCascade
    vDegree := 3;
    vPos0 := Pos(sSatBldcur, vTmpLine);
    vIsBldcur := vPos0 > 0;
    if vIsBldcur then
    begin
      ReadParam(vTmpLine, vPos0, vCount0);
      Inc(vPos0, vCount0);
      vTmpStr := ReadParam(vTmpLine, vPos0, vCount);
      if (vTmpStr <> sSatOpen)and(vTmpStr <> sSatPeriodic) then
        Inc(vPos0, vCount0)
      else
        vPos0 := -1;
    end;

    vTmpStr := vTmpLine;
//    vIsParCur := Pos(sSatParcur, vTmpStr) > 0;
//    vIsExactCur := Pos(sSatExactcur, vTmpStr) > 0;
    vOpen := GetPosNext(sSatOpen, vTmpStr);
    vClose := GetPosNext(sSatClosed, vTmpStr);
    vPeriodic := GetPosNext(sSatPeriodic, vTmpStr);
    vNubs := GetPosNext(sSatNubs, vTmpStr);
    vNurbs := GetPosNext(sSatNurbs, vTmpStr);
    vPos := MaxI(vNubs, vNurbs);
    if vPos > 0 then
    begin
      repeat
      until ReadParamAsInteger(vTmpStr, vPos, vDegree) <> 0;
    end;
    vPos := MaxI(vPos, MaxI(MaxI(vOpen, vPeriodic), vClose));
    if (vPos <> 0) and (vPos0 <> -1) then
    begin
      vSpline := TsgDXFSpline(CreateEntity(TsgDXFSpline));
      try
        vKnotParamsCount := 0;
        repeat
        until ReadParamAsInteger(vTmpStr, vPos, vKnotParamsCount) <> 0;
        while vKnotParamsCount > 0 do
        begin
          vKnotCount := 0;
          repeat
          until ReadParamAsFloat(vTmpStr, vPos, vKnotValue) <> 0;
          repeat
          until ReadParamAsInteger(vTmpStr, vPos, vKnotCount) <> 0;
          while vKnotCount > 0 do
          begin
            TsgDXFSplineAccess(vSpline).AddKnot(vKnotValue);
            Dec(vKnotCount);
          end;
          Dec(vKnotParamsCount);
        end;
        if (vSpline.Knots <> nil) and (vSpline.Knots.Count >= 2 + Integer(vIsBldcur)) then
        begin
          vReadWeight := Byte(vNurbs > 0);
          vControlCount := vSpline.Knots.Count + 1 - vDegree;
//          if (vReadWeight = 0) and FACIS.Encoded then
//          begin
//            if vIsParcur or (vIsExactcur and (vPeriodic = 0)) then
//              vReadWeight := 2;
//          end;
          repeat
            J := 0;
            while (J < 3) and ReadValue(vControl.V[J]) do
              Inc(J);
            if J >= 3 then
            begin
              vSpline.Controls.Add(vControl);
              case vReadWeight of
                1:
                  begin
                    ReadValue(vValue);
                    vSpline.AddWeight(vValue);
                  end;
                2:  ReadParamAsFloat(vTmpStr, vPos, vValue);
              end;
            end;
            Dec(vControlCount);
          until (J < 3) or (vPos >= Length(vTmpStr)) or (vControlCount <= 0);
          if vSpline.ControlCount < 2 then
            FreeAndNil(vSpline);
        end
        else
          FreeAndNil(vSpline);
      finally
        if vSpline <> nil then
        begin
          if vDegree > 0 then
          begin
            vSpline.Degree := vDegree;
            if vDegree = 2 then
            begin
              vSpline.Flags := vSpline.Flags or 4;
            end;
          end;
          if (vSpline.KnotCount > 0) and (vSpline.KnotCount - vSpline.ControlCount < 4) then
          begin
            vSpline.Knots.Insert(0, vSpline.Knots.First);
            vSpline.Knots.Add(vSpline.Knots.Last);
          end;
          AddEntity(vSpline);
        end;
      end;
    end;
  end;
end;

function TsgSATParser.GetSubString(AStr: string; AIndex: Integer): string;
var
  vCount, J, K: Integer;
begin
  Result := '';
  if Length(AStr) > 0 then
  begin
    Result := ' ';
    J := 0;
    vCount := -1;
    repeat
      K := J + 1;
      J := StringScan(FDelimiter, AStr, K);
      Inc(vCount);
      if vCount = AIndex then
      begin
        Result := Copy(AStr, K, J - K);
        Break;
      end;
    until (J = 0);
  end;
end;

function TsgSATParser.GetPtInxBodyLump: Integer;
begin
  Result := CheckIndex(cntPtInxBodyLump);
end;

function TsgSATParser.GetPtInxBodyTransform: Integer;
begin
  Result := CheckIndex(cntPtInxBodyTransform);
end;

function TsgSATParser.GetPtInxCoedgeEdge: Integer;
begin
  Result := CheckIndex(cntPtInxCoedgeEdge);
end;

function TsgSATParser.GetPtInxCoedgeNextCoedge: Integer;
begin
  Result := CheckIndex(cntPtInxCoedgeNextCoedge);
end;

function TsgSATParser.GetPtInxEdgeCurve: Integer;
begin
  Result := CheckIndex(cntPtInxEdgeCurve);
end;

function TsgSATParser.GetPtInxEdgeEndVertex: Integer;
begin
  Result := CheckIndex(cntPtInxEdgeEndVertex);
end;

function TsgSATParser.GetPtInxEdgeStartVertex: Integer;
begin
  Result := CheckIndex(cntPtInxEdgeStartVertex);
end;

function TsgSATParser.GetPtInxFaceFirstLoopBoundingFace: Integer;
begin
  Result := CheckIndex(cntPtInxFaceFirstLoopBoundingFace);
end;

function TsgSATParser.GetPtInxFaceNextFace: Integer;
begin
  Result := CheckIndex(cntPtInxFaceNextFace);
end;

function TsgSATParser.GetPtInxFaceSurfaceOnWhichFaceLies: Integer;
begin
  Result := CheckIndex(cntPtInxFaceSurfaceOnWhichFaceLies);
end;

function TsgSATParser.GetPtInxLoopFirstCoedge: Integer;
begin
  Result := CheckIndex(cntPtInxLoopFirstCoedge);
end;

function TsgSATParser.GetPtInxLoopNextLoopInBoundaryOfFace: Integer;
begin
  Result := CheckIndex(cntPtInxLoopNextLoopInBoundaryOfFace);
end;

function TsgSATParser.GetPtInxLumpFirstShellInLump: Integer;
begin
  Result := CheckIndex(cntPtInxLumpFirstShellInLump);
end;

function TsgSATParser.GetPtInxLumpNextLump: Integer;
begin
  if Version >= cntSatDefVersion then
    Result := cntPtInxLumpNextLump
  else
    Result := cntPtInxLumpNextLumpEarlyVersion;
end;

function TsgSATParser.GetPtInxShellFirstFaceInShell: Integer;
begin
  Result := CheckIndex(cntPtInxShellFirstFaceInShell);
end;

function TsgSATParser.GetPtInxShellNextShell: Integer;
begin
  Result := CheckIndex(cntPtInxShellNextShell);
end;

function TsgSATParser.GetPtInxVertexPoint: Integer;
begin
  Result := CheckIndex(cntPtInxVertexPoint);
end;

function TsgSATParser.GetPtInxVertexTVertexVertexPoint: Integer;
begin
  Result := CheckIndex(cntPtInxVertexTVertexVertexPoint);
end;

function TsgSATParser.GetPtRecInxBeforeDataValues: Integer;
begin
  Result := CheckIndex(2);
end;

function TsgSATParser.GetReversed(const AIndex: Integer;
      const AReversedStr: string = sSatReversed): Integer;
var
  IndexReverse, IndexForward: Integer;

begin
  IndexReverse := AnsiPos(AReversedStr, SATStrings[AIndex]);
  IndexForward := AnsiPos(sSatForward, SATStrings[AIndex]);
  if (IndexForward > 0) and (IndexReverse > 0) then
  begin
    if IndexForward < IndexReverse then
      Result := 0
    else
      Result := IndexReverse;
  end
  else
    Result := IndexReverse;
end;

function TsgSATParser.GetContentData(AIndex: Integer): string;
//var
//  vPos: Integer;
begin
  Result := StringTrim(SATStrings[AIndex], sSatSubtypeStart, sSatSubtypeEnd);
  if Length(Result) > 0 then
  begin
//    vPos := StringScan(sSatSubtypeStart, Result, 1);
//    if vPos > 0 then
//      Delete(Result, vPos, Length(Result) - vPos);
  end
  else
    Result := SATStrings[AIndex];
end;

function TsgSATParser.GetErrorData: Integer;
begin
  Status := False;
  Result := -MaxInt;
end;

function TsgSATParser.GetFileHeader: TsgSATFileHeader;
begin
  Result := FHeader;
end;

function TsgSATParser.GetInterval(var S: string): string;
begin
  Result := '';
  if (AnsiPos('F', S) = 0) and (AnsiPos('I', S) = 0) then Exit;
  if S = '' then Exit;
  if S[1] = FDelimiter then Delete(S, 1, 1);
  if S[1] = 'F' then
  begin
    Delete(S, 1, 1);
    Result := 'F';
  end
  else
  begin
    Result := 'I' + FDelimiter;
    Delete(S, 1, 1);
    if S = '' then Exit;
    if S[1] = FDelimiter then Delete(S, 1, 1);
    Result := Result + Copy(S, 1, AnsiPos(FDelimiter, S) - 1);
  end;
end;

function TsgSATParser.GetNameValueOfString(const StrIndex: Integer): string;
var
  vStr: string;
  I, vPos: Integer;
begin
  Result := '';
  vPos := 0;
  vStr := LowerCase(SATStrings[StrIndex]);
  if Status and (vStr <> '') then
  begin
    for I := 1 to Length(vStr) do
    begin
{$IFDEF SGDEL_2009}
      if CharInSet(vStr[I], ['a'..'z']) then
{$ELSE}
      if vStr[I] in ['a'..'z'] then
{$ENDIF}
      begin
        vPos := I;
        Break;
      end;
    end;
  end;
  if vPos > 0 then
  begin
    Result := Copy(SATStrings[StrIndex], vPos, MaxInt);
    vPos := Pos(FDelimiter, Result);
    if vPos <> 0 then
      Result := Copy(Result, 1, vPos - 1)
    else
      Status := False;
  end
  else
    Status := False;
end;

function TsgSATParser.GetPoint(AIndex: Integer): TFPoint;
var
  vStr, S: string;
  vCode: Integer;
begin
  Result := cnstFPointZero;
  vStr := GetStrWithDataValues(AIndex, GetPtRecInxBeforeDataValues);
  if Status and (Length(vStr) > 0) then
  begin
    S := GetSubString(vStr, 0);
    Result.X := StrToVal(S, vCode);
    S := GetSubString(vStr, 1);
    Result.Y := StrToVal(S, vCode);
    S := GetSubString(vStr, 2);
    Result.Z := StrToVal(S, vCode);
  end
  else
    Status := False;
end;

function TsgSATParser.GetPosNext(const ASubStr, AStr: string): Integer;
begin
  Result := Pos(ASubStr, AStr);
  if Result > 0 then
    Inc(Result, Length(ASubStr));
end;

function TsgSATParser.GetVersion: Integer;
begin
  Result := FHeader.Version;
end;

function TsgSATParser.GetVertex(AIndex: Integer): TFPoint;
var
  vIndex: Integer;
  vStr: string;
begin
  Result := cnstFPointZero;
  vStr := SATStrings[AIndex];
  if Status and (Length(vStr) > 0) then
  begin
    if AnsiPos(sSatTVertex, vStr) = 0 then
      vIndex := PtRecFindByIndex(AIndex, GetPtInxVertexPoint, [sSatPoint])
    else
      vIndex := PtRecFindByIndex(AIndex, GetPtInxVertexTVertexVertexPoint,
        [sSatPoint]);
    vStr := SATStrings[vIndex];
    if AnsiPos(sSatPoint, vStr) <> 0 then
      Result := GetPoint(vIndex)
    else
      if AnsiPos(sSatAttrib, vStr) = 0 then
        Result := GetVertex(vIndex)
      else
        Status := False;
  end;
end;

procedure TsgSATParser.LoadHeaderFromStrList(const HeaderStrs: TStringList);
var
  S: string;
  vPtRecsInBodyCount, vFirstBodyIndex: Integer;
begin
  Status := True;
  S := HeaderStrs.Text;
  FHeader.Version := StrToIntDef(GetSubString(S, 0), cntSatDefVersion);
  FHeader.VersionOriginal := FHeader.Version;
  FHeader.TotalNumRecords := StrToIntDef(GetSubString(S, 1), 0);
  FHeader.TotalNumRecords := StrToIntDef(GetSubString(S, 2), 0);
  FHeader.LeastSignBit := StrToIntDef(GetSubString(S, 3), 0);
  if FBodiesIndexes.Count > 0 then
  begin
    vFirstBodyIndex := FBodiesIndexes[0];
    if GetNameValueOfString(vFirstBodyIndex) <> sSatBody then
      Dec(vFirstBodyIndex);
    if GetNameValueOfString(vFirstBodyIndex) = sSatBody then
    begin
      vPtRecsInBodyCount := SubStrCount(sSatRecNumPtr, SATStrings[vFirstBodyIndex]);
      if vPtRecsInBodyCount < 5 then
        FHeader.Version := Math.Min(FHeader.Version, cntSatDefVersion - 1)
      else
        FHeader.Version := Math.Max(FHeader.Version, cntSatDefVersion);
    end;
  end;
end;

procedure TsgSATParser.MakeCurve(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
var
  vStr: string;
begin
  if Status then
  begin
    vStr := GetNameValueOfString(AIndex);
    case StrIndex(vStr, sSatTypeCurve) of
      0: AddEllipseCurve(ABrepEntity, AIndex);
      1: AddIntCurve(ABrepEntity, AIndex);
      2: AddStraightCurve(ABrepEntity, AIndex); //Line
      3: AddHelixCurve(ABrepEntity, AIndex);
      -1: FBadSurface := True;
    end;
  end;
end;

procedure TsgSATParser.MakeEdge(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer);
var
  vIndex, vPos: Integer;
  vStr: string;
  vEdge: TsgBrepEdge;

  function SetVertex(var FPoint: TFPoint; const PtNum: Integer): Boolean;
  const
    cntVertexesArray: array[0..1] of string = (sSatVertex, sSatTVertex);
  var
    vIndex: Integer;
  begin
    vIndex := CheckSatName(PtRecFindByIndex(AIndex, PtNum, cntVertexesArray),
      cntVertexesArray);
    Result := Status;
    if Result then
      FPoint := GetVertex(vIndex);
  end;

  function CheakParamVersion(const AStr: string): Boolean;
  var
    vPosLoc: Integer;
    vStrLoc: string;
  begin
    Result := True;
    if Length(AStr) = 0 then
      Exit;
    vPosLoc := 1;
    ReadString(AStr, vPosLoc);
    vStrLoc := ReadString(AStr, vPosLoc);
    if Pos('$', vStrLoc) <= 0 then
      Result := False;
  end;

begin
  if Status then
  begin
    if not SetVertex(FPoints[0], GetPtInxEdgeStartVertex) then Exit;
    if not SetVertex(FPoints[1], GetPtInxEdgeEndVertex) then Exit;

    vEdge := TsgBrepCoEdge(ABrepEntity).AddEdge;
{$IFDEF SG_BREP_DEBUG}
    vEdge.FIndex := AIndex;
{$ENDIF}
    vStr := GetStrWithDataValues(AIndex, GetPtRecInxBeforeDataValues);

    vEdge.FPointA := FPoints[0];
    vEdge.FPointB := FPoints[1];

    if not CheakParamVersion(vStr) then
    begin
      vPos := 1;
      ReadString(vStr, vPos);
      vEdge.StartParam := ReadFloat(vStr, vPos);
      ReadString(vStr, vPos);
      vEdge.EndParam := ReadFloat(vStr, vPos);
    end;

    vEdge.FOrientation := Integer(GetReversed(AIndex) <> 0);

    vIndex := PtRecFindByIndex(AIndex, GetPtInxEdgeCurve, [sSatCurve]);
    if (vIndex > 0) and Status then
      MakeCurve(vEdge, vIndex);
  end;
end;

function TsgSATParser.MakeBody(ARootBrep: TList; AIndex: Integer): Integer;
var
  vIndex: Integer;
  vBody: TsgBody;
  vPos: Integer;
  vStr: string;
  vMatrix: TFMatrix;
  vMatrixPlus: TsgFloat;
begin
  Result := AIndex;
  if Status then
  begin
    // Transform
    vIndex := PtRecFindByIndex(AIndex, GetPtInxBodyTransform, [sSatTransform]);
    if vIndex > 0 then
    begin
      vStr := GetStrWithDataValues(vIndex, 1);
      vPos := 1;
      if Version >= cntSatDefVersion then
        ReadFloat(vStr, vPos);
      vMatrix.EX := ReadFPoint(vStr, vPos);
      vMatrix.EY := ReadFPoint(vStr, vPos);
      vMatrix.EZ := ReadFPoint(vStr, vPos);
      vMatrix.E0 := ReadFPoint(vStr, vPos);
      vMatrixPlus := ReadFloat(vStr, vPos);
    end
    else
    begin
      vMatrix := cnstIdentityMat;
      vMatrixPlus := 1;
    end;

    // Lump
    vIndex := PtRecFindByIndex(AIndex, GetPtInxBodyLump, [sSatLump]);
    if vIndex < 0 then
       Result := GetErrorData
     else
     begin
       vBody := TsgBody.Create;
{$IFDEF SG_BREP_DEBUG}
       vBody.FIndex := vIndex;
{$ENDIF}
       vBody.FMatrix := vMatrix;
       vBody.FMatrixPlus := vMatrixPlus;
       ARootBrep.Add(vBody);
       while (vIndex > 0) and Status do
         vIndex := MakeLump(TsgEntityBrepTopology(ARootBrep.Last), vIndex);
     end;
  end;
end;

function TsgSATParser.MakeCoEdge(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer): Integer;
const
  cntEdgesArray: array[0..1] of string = (sSatEdge, sSatTEdge);
var
  vIndex: Integer;
  vCoEdge: TsgBrepCoEdge;
begin
  if Status then
  begin
    vIndex := CheckSatName(PtRecFindByIndex(AIndex, GetPtInxCoedgeEdge, cntEdgesArray),
      cntEdgesArray);

    FCoEdgeReversed := GetReversed(AIndex) <> 0;
    vCoEdge := TsgBrepLoop(ABrepEntity).AddCoEdge;
    vCoEdge.FOrientation := Integer(FCoEdgeReversed);
{$IFDEF SG_BREP_DEBUG}
    vCoEdge.FIndex := AIndex;
{$ENDIF}
    MakeEdge(vCoEdge, vIndex);
    Result := PtRecFindByIndex(AIndex, GetPtInxCoedgeNextCoedge, [sSatCoedge,
      sSatTCoedge], 1, True);
  end
  else
    Result := GetErrorData;
end;

function TsgSATParser.MakeLoop(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer): Integer;
const
  cntCoEdgesArray: array[0..1] of string = (sSatCoedge, sSatTCoedge);
var
  vIndex, vFirst: Integer;
  vLoop: TsgBrepLoop;
begin
  if Status then
  begin
    //???
    if not IsLoadMeshBuilderDll then
      FACIS.AddEntity(TsgDXFEntity.Create);
    vFirst := CheckSatName(PtRecFindByIndex(AIndex, GetPtInxLoopFirstCoedge,
      cntCoEdgesArray), cntCoEdgesArray);
    vLoop := TsgBrepFace(ABrepEntity).AddLoop;
{$IFDEF SG_BREP_DEBUG}
    vLoop.FIndex := AIndex;
{$ENDIF}
    vIndex := vFirst;
    repeat
      if Status then
        vIndex := MakeCoEdge(vLoop, vIndex)
      else
        Break;
    until vIndex = vFirst;
    if Status then
      Result := PtRecFindByIndex(AIndex, GetPtInxLoopNextLoopInBoundaryOfFace,
        [sSatLoop])
    else
      Result := GetErrorData;
  end
  else
    Result := GetErrorData;
end;

function TsgSATParser.MakeFace(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer): Integer;
var
  vIndexLoop, vSurfaceIndex: Integer;
  vFace: TsgBrepFace;
begin
  vFace := TsgBrepShell(ABrepEntity).AddFace;
{$IFDEF SG_BREP_DEBUG}
  vFace.FIndex := AIndex;
{$ENDIF}
  FBadSurface := False;

  vFace.FOrientation := Integer(GetReversed(AIndex) > 0);

  vSurfaceIndex := PtRecFindByIndex(AIndex, GetPtInxFaceSurfaceOnWhichFaceLies,
        [sSatSurface], MaxInt);
  if (vSurfaceIndex > 0) and Status then
    MakeSurface(vFace, vSurfaceIndex);

  vIndexLoop := PtRecFindByIndex(AIndex, GetPtInxFaceFirstLoopBoundingFace, [sSatLoop]);
  while (vIndexLoop > 0) and Status do
  begin
        vIndexLoop := MakeLoop(vFace, vIndexLoop);
  end;

  if FBadSurface then
  begin
    if Assigned(vFace.Sufface) then
      vFace.Sufface.Free;
    vFace.Sufface := nil;
  end
  else
  begin
{$IFDEF SG_BREP_DEBUG}
    if Assigned(vFace.Sufface) then
      vFace.Sufface.FIndex := vSurfaceIndex;
{$ENDIF}
  end;
  Result := PtRecFindByIndex(AIndex, GetPtInxFaceNextFace, [sSatFace]);
end;

function TsgSATParser.MakeShell(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer): Integer;
var
  vIndex: Integer;
  vShell: TsgBrepShell;
begin
  vShell := TsgBrepLump(ABrepEntity).AddShell;
{$IFDEF SG_BREP_DEBUG}
  vShell.FIndex := AIndex;
{$ENDIF}
  vIndex := PtRecFindByIndex(AIndex, GetPtInxShellFirstFaceInShell, [sSatFace],
    1, False, True);
  while (vIndex > 0) and Status do
    vIndex := MakeFace(vShell, vIndex);
  Result := PtRecFindByIndex(AIndex, GetPtInxShellNextShell, [sSatShell]);
end;

function TsgSATParser.MakeSurface(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer): Integer;
begin
  Result := -1;
  case StrIndex(GetNameValueOfString(AIndex), sSatTypeSurface) of
    0: AddConeSurface(ABrepEntity, AIndex);
    1: AddPlanSurface(ABrepEntity, AIndex);
    2: AddTorusSurface(ABrepEntity, AIndex);
    3: AddSphereSurface(ABrepEntity, AIndex);
    4: AddSplineSurface(ABrepEntity, AIndex);
  end;
end;

function TsgSATParser.MakeLump(ABrepEntity: TsgEntityBrepTopology; AIndex: Integer): Integer;
var
  vIndex: Integer;
  vLump : TsgBrepLump;
begin
  vLump := TsgBody(ABrepEntity).AddLump;
{$IFDEF SG_BREP_DEBUG}
  vLump.FIndex := AIndex;
{$ENDIF}
  vIndex := PtRecFindByIndex(AIndex, GetPtInxLumpFirstShellInLump, [sSatShell], 1,
    False, True);
  while (vIndex > 0) and Status do
  begin
    vIndex := MakeShell(vLump, vIndex);
  end;
  Result := PtRecFindByIndex(AIndex, GetPtInxLumpNextLump, [sSatLump]);
end;

function TsgSATParser.Parse(const AEntity: TsgDXFACISEntity): Boolean;
const
  cntMaxTimeACISLoading = 180; //sec
var
  I: Integer;
  vInitData: TsgInitMeshBuilderData;
  vParams: PsgParamTriangle;
{$IFDEF SG_BREP_DEBUG}
  J, K, M, N, L, S, P: Integer;
  vLump: TsgBrepLump;
  vBody: TsgBody;
  vShell: TsgBrepShell;
  vFace: TsgBrepFace;
  vLoop: TsgBrepLoop;
  vCoEdge: TsgBrepCoEdge;
  vEdge: TsgBrepEdge;
  vVertices : TsgBrepVertices;
  Index: Integer;
  TestStrings: TStringList;
  vLevelTab: Integer;
  vStrTab: string;

  function GetSATSt(const AIndex: Integer): string;
  begin
    Result := GetSATStringsClear(AIndex);
  end;

{$ENDIF}
begin
  FDelimiter := AEntity.Delimiter;
  FEofStr := AEntity.EofStr;
  FACIS := AEntity;
  Result := (FACIS <> nil) and (FConverter <> nil) and
    (FACIS.ProprietaryData.Count > 0);
  if not Result then
    Exit;
  FBody := TsgBrepRoot(FACIS.Brep).Body;
  DecodeProprietaryData;
  if not PrepareForParcing then
  begin
    Result := False;
    Exit;
  end;
  Status := True;
  FNeedToDec := False;

{$IFDEF SG_BREP_DEBUG}
  FSATStrings.SaveToFile('D:\Test.txt');
{$ENDIF}

  FSatCreateEntity := TsgSatCreatorEntity.CreateEx(Self, FACIS);
  try
    try
      for I := 0 to FBodiesIndexes.Count - 1 do
      begin
        MakeBody(FBody, FBodiesIndexes[I]);
      end;
      Result := Status;
    except
      AEntity.Clear;
    end;

    ZeroMemory(@vInitData, Sizeof(vInitData));
    vInitData.DrawWireFunc := @CallBackDrawWireVertexDraw;
    vInitData.DrawISOFunc := @CallBackDrawISOVertexDraw;
    //vInitData.DrawTestFunc := @CallBackDrawTestVertexDraw;
    vInitData.Self := Pointer(Self);
    vInitData.Creator := Pointer(FSatCreateEntity);
    New(vParams);
    try
      ZeroMemory(vParams, SizeOf(vParams));
      vParams^.ASelf := vInitData.Creator;
      vInitData.BeginSegment := @BeginSegment;
      vInitData.EndSegment := @EndSegment;
      vInitData.MeshParam := vParams;
      FACIS.GetMeshBrep(vInitData);
    finally
      Dispose(vParams);
    end;
  finally
    FConverter.LoadsGroup(FACIS);
    FSatCreateEntity.Free;
  end;

{$IFDEF SG_BREP_DEBUG}

  Index := 0;

  TestStrings :=  TStringList.Create;
  vLevelTab := 0;
  try
    for I := 0 to FBody.Count - 1 do
    begin
      vBody := TsgBody(FBody[I]);
      TestStrings.Add('['+IntToStr(vBody.FIndex)+'] '+GetSATSt(vBody.FIndex));
      vStrTab := StringOfChar('.',2);
      for J := 0 to vBody.Lumps.Count - 1 do
      begin
        vLump := vBody.Lumps[J];
        TestStrings.Add(vStrTab+'['+IntToStr(vLump.FIndex)+'] '+GetSATSt(vLump.FIndex));
        vStrTab := StringOfChar('.',4);
        for K := 0 to vLump.Shell.Count - 1 do
        begin
          vShell := TsgBrepShell(vLump.Shell[K]);
          TestStrings.Add(vStrTab+'['+IntToStr(vShell.FIndex)+'] '+GetSATSt(vShell.FIndex));
          vStrTab := StringOfChar('.',6);
          for M := 0 to vShell.Face.Count - 1 do
          begin
            vFace := TsgBrepFace(vShell.Face[M]);

            //
            if not Assigned(vFace.Sufface) then
            begin
              vStrTab := StringOfChar('.',6);
              Continue;
            end;
            //sePlaneSurface seTorusSurface seSphereSurface seConeSurface seExactSplineSurface
//            if Assigned(vFace.Sufface) and
//              (vFace.Sufface.BrepEntType <> seTorusSurface) then
//            begin
//              vStrTab := StringOfChar('.',6);
//              Continue;
//            end
//            else
//            begin
//              Inc(Index);
//              if not((Index >= 22) and (Index <= 22) ) then//if not ((Index = 2) or (Index = 4)) then  //16
//                Continue;
//            end;

            TestStrings.Add(vStrTab+'['+IntToStr(vFace.FIndex)+'] '+GetSATSt(vFace.FIndex));
            vStrTab := StringOfChar('.',8);
            if Assigned(vFace.Sufface)then
            begin
              TestStrings.Add(vStrTab+'['+IntToStr(vFace.Sufface.FIndex)+'] '+GetSATSt(vFace.Sufface.FIndex));
            end
            else
              TestStrings.Add(vStrTab+'nil');

            for N := 0 to vFace.Loops.Count - 1 do
            begin
              vLoop := TsgBrepLoop(vFace.Loops[N]);
              TestStrings.Add(vStrTab+'['+IntToStr(vLoop.FIndex)+'] '+GetSATSt(vLoop.FIndex));
              vStrTab := StringOfChar('.',10);
              for L := 0 to vLoop.CoEdges.Count - 1 do
              begin
                vCoEdge := TsgBrepCoEdge(vLoop.CoEdges[L]);
                TestStrings.Add(vStrTab+'['+IntToStr(vCoEdge.FIndex)+'] '+GetSATSt(vCoEdge.FIndex));
                vStrTab := StringOfChar('.',12);
                for S := 0 to vCoEdge.Edges.Count - 1 do
                begin
                  vEdge := TsgBrepEdge(vCoEdge.Edges[S]);
                  TestStrings.Add(vStrTab+'['+IntToStr(vEdge.FIndex)+'] '+GetSATSt(vEdge.FIndex));
                  vStrTab := StringOfChar('.',14);


//                  //!!!!
//                  if vEdge.Curve.BrepEntType <> seEllipsCurve then
//                    TestStrings.Add(vStrTab+'skip')
//                  else
//                  begin
//                  //!!!!!
//
                  if Assigned(vEdge.Curve) then
                  begin
                    TestStrings.Add(vStrTab+'['+IntToStr(vEdge.Curve.FIndex)+'] '+GetSATSt(vEdge.Curve.FIndex));
                  end
                  else
                    TestStrings.Add(vStrTab+'nil');
//
//                  end;//!!!!!!!!!!!

                  for P := 0 to vEdge.Vertices.Count - 1 do
                  begin
                    vVertices := TsgBrepVertices(vEdge.Vertices[P]);
                    TestStrings.Add(vStrTab+'['+IntToStr(vVertices.FIndex)+'] '+GetSATSt(vVertices.FIndex));
                  end;
                  vStrTab := StringOfChar('.',12);
                end;
                vStrTab := StringOfChar('.',10);
              end;
              vStrTab := StringOfChar('.',8);
            end;
            vStrTab := StringOfChar('.',6);
          end;
          vStrTab := StringOfChar('.',4);
        end;
        vStrTab := StringOfChar('.',2);
      end;
    end;
  finally
    TestStrings.SaveToFile('D:\Test2.txt');
    TestStrings.Free;
  end;
{$ENDIF}

end;

function TsgSATParser.PrepareForParcing: Boolean;
var
  I, vPos, vFirstBodyIndex, vBodiesCount: Integer;
  vHeaderStrings: TStringList;
  S, S1: string;

  procedure ParseTermination;
  var
    vTmpStrs: TStringList;
  begin
    vTmpStrs := TStringList.Create;
    try
      vTmpStrs.Assign(FSATStrings);
      FSATStrings.Clear;
      I := 0;
      while I <= vTmpStrs.Count - 1 do
      begin
        S := vTmpStrs[I];
        vPos := Pos(FEofStr, S);
        if vPos = 0 then
        begin
          while True do
          begin
            Inc(I);
            if (I > vTmpStrs.Count - 1) then Break;
            S1 := vTmpStrs[I];
            S := S + (*FDelimiter +*) S1;
            vPos := Pos(FEofStr, S1);
            if vPos > 0 then Break;
          end;
          //ReplaceToPos(S, #9, FDelimiter, Length(S));
          while ReplaceToPos(S, FDelimiter + FDelimiter, FDelimiter, Length(S)) > 0 do;
        end;
        S := StringTrimLeftRight(S);
        FSATStrings.Add(S);
        Inc(I);
      end;
    finally
      vTmpStrs.Free;
    end;
  end;

begin
  Result := False;
  FBodiesIndexes.Clear;
  vFirstBodyIndex := -1;
  vBodiesCount := 0;
  for I := 0 to SATStringsCount - 1 do
    if (Pos(sSatBody + FDelimiter, SATStrings[I]) > 0) then
    begin
      Inc(vBodiesCount);
      if FACIS.SATDirect then
        FBodiesIndexes.Add(vBodiesCount - 1)
      else
        FBodiesIndexes.Add(vBodiesCount);
      if vFirstBodyIndex < 0 then
        vFirstBodyIndex := I;
    end
    else
    begin
      if vBodiesCount > 0 then
        Break;
    end;
  if FBodiesIndexes.Count = 0 then Exit;
  vHeaderStrings := TStringList.Create;
  try
    while vFirstBodyIndex > 0 do
    begin
      vHeaderStrings.Add(FSATStrings[0]);
      FSATStrings.Delete(0);
      Dec(vFirstBodyIndex);
    end;
    LoadHeaderFromStrList(vHeaderStrings);
  finally
    vHeaderStrings.Free;
  end;
  if not FACIS.SATDirect then
  begin
    ParseTermination;
    if Version >= cntSatDefVersion then
      FSATStrings.Insert(0, sSatDefHeaderString)
    else
      for I := 0 to FBodiesIndexes.Count - 1 do
        FBodiesIndexes[I] := FBodiesIndexes[I] - 1;
  end
  else
  begin
    ParseTermination;
  end;
  Result := True;
end;

function TsgSATParser.PtRecPos(const StrIndex, PointerIndex: Integer): Integer;
begin
  Result := StringPosNum(sSatRecNumPtr, SATStrings[StrIndex], PointerIndex, 1);
end;

{ TsgBrepRoot }

constructor TsgBrepRoot.Create;
begin
  inherited Create;
  FBody := TList.Create;
end;

destructor TsgBrepRoot.Destroy;
begin
  FreeList(FBody);
  inherited Destroy;
end;

function TsgBrepRoot.AddSurfaceToBrepBuilder(AContext: PsgContext;
  AFace: TsgBrepFace): Boolean;
var
  vConeSurfaceData: TsgConeData;
  vConeSurface: TsgBrepConeSurface;
  vPlaneSurfaceData: TsgPlaneData;
  vPlaneSurface: TsgBrepPlaneSurface;
  vSplineSurfaceData: TsgSplineSurfaceData;
  vSplineSurface: TsgBrepExactSplineSurface;
  vTorusSurfaceData: TsgTorusData;
  vTorusSurface: TsgBrepTorusSurface;
  vSphereSurfaceData: TsgSphereData;
  vSphereSurface: TsgBrepSphereSurface;
  vSurface: TsgBrepSurface;

begin
  Result := False;
  vSurface := AFace.Sufface;
  if not Assigned(vSurface) then
    Exit;
  case vSurface.BrepEntType of
    seSphereSurface:
      begin
        vSphereSurface := TsgBrepSphereSurface(vSurface);
        vSphereSurfaceData.Positon.Center := MakeVertex(vSphereSurface.Center);
        vSphereSurfaceData.PoleDir := MakeVertex(vSphereSurface.PoleDir);
        vSphereSurfaceData.Radius := vSphereSurface.Radius;
        vSphereSurfaceData.UVOridir := MakeVertex(vSphereSurface.UVOridir);
        vSphereSurfaceData.ReverseV := Integer(vSphereSurface.ReverseV);
        vSphereSurfaceData.ReverseFace := Integer(AFace.FOrientation);
        Result := sgAddSphereSurface(AContext, vSphereSurfaceData) = RESULT_SUCCESS;
      end;

    seConeSurface:
      begin
        vConeSurface := TsgBrepConeSurface(vSurface);
        vConeSurfaceData.BaseEllipse.Positon.Center := MakeVertex(vConeSurface.Base.Center);
        vConeSurfaceData.BaseEllipse.Positon.Normal := MakeVertex(vConeSurface.Base.Normal);
        vConeSurfaceData.BaseEllipse.MajorAxis := MakeVertex(vConeSurface.Base.MajorAxis);
        vConeSurfaceData.BaseEllipse.RadiusRatio := vConeSurface.Base.RadiusRatio;
        vConeSurfaceData.SinAngle := vConeSurface.SineAngle;
        vConeSurfaceData.CosinAngle := vConeSurface.CosineAngle;
        vConeSurfaceData.ReverseU := Integer(vConeSurface.ReverseU);
        vConeSurfaceData.ReverseFace := Integer(AFace.FOrientation);

        Result := sgAddConeSurface(AContext, vConeSurfaceData) = RESULT_SUCCESS;
      end;
    sePlaneSurface:
      begin
        vPlaneSurface := TsgBrepPlaneSurface(vSurface);
        vPlaneSurfaceData.Positon.Center := MakeVertex(vPlaneSurface.RootPoint);
        vPlaneSurfaceData.Positon.Normal := MakeVertex(vPlaneSurface.Normal);
        vPlaneSurfaceData.UDeriv := MakeVertex(vPlaneSurface.UDeriv);
        vPlaneSurfaceData.ReverseV := Integer(vPlaneSurface.ReverseV);
        vPlaneSurfaceData.ReverseFace := Integer(AFace.FOrientation);

        Result := sgAddPlaneSurface(AContext, vPlaneSurfaceData) = RESULT_SUCCESS;
      end;
    seExactSplineSurface:
      begin
        vSplineSurface := TsgBrepExactSplineSurface(vSurface);
        //Spline U
        vSplineSurfaceData.SplineU.Degree := vSplineSurface.Bs3SurfaceU.Degree;
        vSplineSurfaceData.SplineU.Periodic :=
          Integer(vSplineSurface.Bs3SurfaceU.IdentClosere = IndexOfStrings(sSatPeriodic , sSatIdentClosureSurface));
        vSplineSurfaceData.SplineU.CheckRaional := 0;
        vSplineSurfaceData.SplineU.Knots.Count := vSplineSurface.Bs3SurfaceU.Knots.Count;
        vSplineSurfaceData.SplineU.Knots.SizeElement := SizeOf(vSplineSurface.Bs3SurfaceU.Knots.Last);
        vSplineSurfaceData.SplineU.Knots.ListData := vSplineSurface.Bs3SurfaceU.Knots.List;
        vSplineSurfaceData.SplineU.Multiplicities.Count := vSplineSurface.Bs3SurfaceU.Multiplicities.Count;
        vSplineSurfaceData.SplineU.Multiplicities.SizeElement := SizeOf(vSplineSurface.Bs3SurfaceU.Multiplicities.Last);
        vSplineSurfaceData.SplineU.Multiplicities.ListData := vSplineSurface.Bs3SurfaceU.Multiplicities.List;
        //Spline V
        vSplineSurfaceData.SplineV.Degree := vSplineSurface.Bs3SurfaceV.Degree;
        vSplineSurfaceData.SplineV.Periodic :=
          Integer(vSplineSurface.Bs3SurfaceV.IdentClosere = IndexOfStrings(sSatPeriodic , sSatIdentClosureSurface));
        vSplineSurfaceData.SplineV.CheckRaional := 0;
        vSplineSurfaceData.SplineV.Knots.Count := vSplineSurface.Bs3SurfaceV.Knots.Count;
        vSplineSurfaceData.SplineV.Knots.SizeElement := SizeOf(vSplineSurface.Bs3SurfaceV.Knots.Last);
        vSplineSurfaceData.SplineV.Knots.ListData := vSplineSurface.Bs3SurfaceV.Knots.List;
        vSplineSurfaceData.SplineV.Multiplicities.Count := vSplineSurface.Bs3SurfaceV.Multiplicities.Count;
        vSplineSurfaceData.SplineV.Multiplicities.SizeElement := SizeOf(vSplineSurface.Bs3SurfaceV.Multiplicities.Last);
        vSplineSurfaceData.SplineV.Multiplicities.ListData := vSplineSurface.Bs3SurfaceV.Multiplicities.List;
        //All data
        vSplineSurfaceData.ControlPointsUV.Count := vSplineSurface.ControlPointsUV.Count;
        vSplineSurfaceData.ControlPointsUV.SizeElement := SizeOf(vSplineSurface.ControlPointsUV.Last);
        vSplineSurfaceData.ControlPointsUV.ListData := vSplineSurface.ControlPointsUV.List;
        vSplineSurfaceData.WeightsUV.Count := vSplineSurface.WeightsUV.Count;
        vSplineSurfaceData.WeightsUV.SizeElement := SizeOf(vSplineSurface.WeightsUV.Last);
        vSplineSurfaceData.WeightsUV.ListData := vSplineSurface.WeightsUV.List;

        vSplineSurfaceData.ReverseFace := Integer(AFace.FOrientation);

        Result := sgAddSplineSurface(AContext, vSplineSurfaceData) = RESULT_SUCCESS;
      end;
    seTorusSurface:
      begin
        vTorusSurface := TsgBrepTorusSurface(vSurface);
        vTorusSurfaceData.Positon.Center := MakeVertex(vTorusSurface.Center);
        vTorusSurfaceData.Positon.Normal := MakeVertex(vTorusSurface.Normal);
        vTorusSurfaceData.MajorRadius := vTorusSurface.MajorRadius;
        vTorusSurfaceData.MinorRadius := vTorusSurface.MinorRadius;
        vTorusSurfaceData.UVOridir := MakeVertex(vTorusSurface.UVOridir);
        vTorusSurfaceData.ReverseV := Integer(vTorusSurface.ReverseV);
        vTorusSurfaceData.ReverseFace := Integer(AFace.FOrientation);
        Result := sgAddTorusSurface(AContext, vTorusSurfaceData) = RESULT_SUCCESS;
      end;
  end;
end;

function TsgBrepRoot.AddCurveToBrepBuilder(AContext: PsgContext;
  AEdge: TsgBrepEdge; AOrientation: Integer): Boolean;
var
  vEllipseData: TsgEllipseData;
  vEllipse: TsgBrepEllipsCurve;
  vBSpline: TsgBSplineData;
  vExactcur: TsgBrepExactCurve;
  vStraightData: TsgStraightData;
  vStraight: TsgBrepStraightCurve;
  vInterval: TsgIntervalData;
  vCurve: TsgBrepCurve;
  vPointA, vPointB: TFPoint;
  vIntervalFlag, vInvertNormal: Integer;

  procedure SetInteval(AInterval: TsgIntervalData;var AIntervalDist: TsgIntervalData);
  begin
    AIntervalDist := AInterval;
  end;

begin
  Result := False;
  vCurve := AEdge.Curve;
  if not Assigned(vCurve) then
    Exit;

  vIntervalFlag := Integer((AEdge.StartParam = MinDouble) or
                  (AEdge.EndParam = MaxDouble));

//  if AEdge.Orientation = 1 then
//  begin
//    vPointB := AEdge.FPointA;
//    vPointA := AEdge.FPointB;
//    vInvertNormal := -1;
//  end
//  else
  begin
    vInvertNormal := 1;
    vPointA := AEdge.FPointA;
    vPointB := AEdge.FPointB;
  end;

  vInterval.RangeaA := AEdge.FStartParam;
  vInterval.RangeaB := AEdge.FEndParam;
  vInterval.PointA := MakeVertex(vPointA);
  vInterval.PointB := MakeVertex(vPointB);
  vInterval.OrientationEdge := AEdge.Orientation;
  vInterval.OrientationCoEdge := AOrientation;

  case vCurve.GetBrepEntType of
    seStraightCurve:
      begin
        vStraight := TsgBrepStraightCurve(vCurve);
        vStraightData.Root := MakeVertex(vStraight.Root);
        vStraightData.Direction := MakeVertex(PtXScalar(vStraight.Direction, vInvertNormal));

        vStraightData.IntervalFlag := vIntervalFlag;
        SetInteval(vInterval, vStraightData.Interval);

        sgAddStraight(AContext, vStraightData);
        Result := True;
      end;
    seEllipsCurve:
      begin
        vEllipse := TsgBrepEllipsCurve(vCurve);
        vEllipseData.Positon.Center := MakeVertex(vEllipse.FCenter);
        vEllipseData.Positon.Normal := MakeVertex(PtXScalar(vEllipse.FNormal, vInvertNormal));
        vEllipseData.MajorAxis := MakeVertex(vEllipse.FMajorAxis);
        vEllipseData.RadiusRatio := vEllipse.FRadiusRatio;

        vEllipseData.IntervalFlag := vIntervalFlag;
        SetInteval(vInterval, vEllipseData.Interval);

        sgAddEllipse(AContext, vEllipseData);
        Result := True;
      end;
    seExactCurve:
      begin
        vExactcur := TsgBrepExactCurve(vCurve);

        vBSpline.Degree := vExactcur.Bs3Curve.Degree;
        vBSpline.Periodic :=
          Integer(vExactcur.Bs3Curve.IdentClosere = IndexOfStrings(sSatPeriodic , sSatIdentClosureCurve));
        vBSpline.CheckRaional := 0;
        vBSpline.ControlPoints.Count := vExactcur.Bs3Curve.ControlPoints.Count;
        vBSpline.ControlPoints.SizeElement := SizeOf(vExactcur.Bs3Curve.ControlPoints.Last);
        vBSpline.ControlPoints.ListData := vExactcur.Bs3Curve.ControlPoints.List;

        vBSpline.Weights.Count := vExactcur.Bs3Curve.Weights.Count;
        vBSpline.Weights.SizeElement := SizeOf(vExactcur.Bs3Curve.Weights.Last);
        vBSpline.Weights.ListData := vExactcur.Bs3Curve.Weights.List;

        vBSpline.Knots.Count := vExactcur.Bs3Curve.Knots.Count;
        vBSpline.Knots.SizeElement := SizeOf(vExactcur.Bs3Curve.Knots.Last);
        vBSpline.Knots.ListData := vExactcur.Bs3Curve.Knots.List;

        vBSpline.Multiplicities.Count := vExactcur.Bs3Curve.Multiplicities.Count;
        vBSpline.Multiplicities.SizeElement := SizeOf(vExactcur.Bs3Curve.Multiplicities.Last);
        vBSpline.Multiplicities.ListData := vExactcur.Bs3Curve.Multiplicities.List;

        vBSpline.IntervalFlag := vIntervalFlag;
        SetInteval(vInterval, vBSpline.Interval);

        sgAddBSpline(AContext, vBSpline);

        Result := True;
      end;
  end;
end;

{ TsgBrepCreateEntity }

function TsgCreatorEntityBase.AddEntityInternal(const AEntity: TsgDXFEntity): TsgDXFEntity;
begin
  if FCurrentBlock = nil then
    Result :=  FBase
  else
  begin
    if FCurrentFace = nil then
      Result := FCurrentBlock
    else
      Result := FCurrentFace;
  end;
  Result.AddEntity(AEntity);
end;

function TsgCreatorEntityBase.AddEntity(const AEntity: TsgDXFEntity): TsgDXFEntity;
begin
  Result := AddEntityInternal(AEntity);
end;

function TsgCreatorEntityBase.GetCurrentParent: TsgDXFEntity;
begin
   Result := FCurrentBlock;
   if Result = nil then
   begin
     Result :=  FBase;
   end
   else
   begin
     if FCurrentFace <> nil then
       Result := FCurrentFace;
   end;
end;

procedure TsgCreatorEntityBase.BeginSegment(const AColor: TsgColorCAD;
  AIndexFaceMap: Integer = -1; Name: String = '');
var
  vBlock: TsgDXFBlock;
  vBrepIndexFace: TsgBrepEntity;
  vInsert: TsgDXFInsert;

  function ExtractName(const AName: string): string;
  const
    cnstSharp = '#';
    cnstSpace = ' ';
    cnstAsk = '?';
    cntsSl = '/';
    cnts1 = '<';
    cnts2 = '>';
  begin
    Result := AName;
    if AnsiPos(cnstSharp, Result) > 0 then
      ReplaceAnsi(Result, cnstSharp, '$23');
    if AnsiPos(cnts1, Result) > 0 then
      ReplaceAnsi(Result, cnts1, '$23');
    if AnsiPos(cnts2, Result) > 0 then
      ReplaceAnsi(Result, cnts2, '$23');
    if AnsiPos(cnstSpace, Result) > 0 then
      ReplaceAnsi(Result, cnstSpace, '$20');
    if AnsiPos(cntsSl, Result) > 0 then
      ReplaceAnsi(Result, cntsSl, '$2F');
    if AnsiPos(cnstAsk, Result) > 0 then
      ReplaceAnsi(Result, cnstAsk, '$3F');
  end;

begin

{$IFDEF CHECK_TIME}
  if not IsCalcTick then
  begin
    TicksLoad := GetTickCount;
    OutputDebugString(PChar(Format('OpenCascade loading time is %s mlsek',
    [FloatToStr(GetTickCount - TicksLoadOpenCascade)])));
    IsCalcTick := True;
  end;
{$ENDIF}

  vBlock := TsgDXFBlock.Create;
  vBlock.ColorCAD := cnstColorCADByBlock;
  FStackBlock.Push(FCurrentBlock);
{$IFDEF SG_BREP_TOPOLOGY}
  FStackTopology.Push(FCurrentTopology);
  FStackInsert.Push(FCurrentInsert);
{$ENDIF}
  vBlock.Name := cnstBrepBlock + ExtractName(Name) + '_' + IntToStr(TsgNativeUINT(vBlock));
  FConverter.Sections[csBlocks].AddEntity(vBlock);
  vInsert := TsgDXFInsert(CreateEntityInternal(TsgDXFInsert));
  AddEntity(vInsert);
  vInsert.Block := vBlock;
  vInsert.ColorCAD := AColor;
{$IFDEF SG_BREP_TOPOLOGY}
  FCurrentInsert := vInsert;
{$ENDIF}
  FCurrentBlock := vBlock;

  case AIndexFaceMap of
    0..MaxInt:
      begin
        vBrepIndexFace := TsgBrepEntity(CreateIndexFace(AIndexFaceMap));
        vBlock.AddEntity(vBrepIndexFace);
        FCurrentFace := vBrepIndexFace;
      end;
    -2:
      begin
        //Blank code - see revision 18825
      end;
    else
      FCurrentFace := nil;
  end;

{$IFDEF SG_BREP_DEBUG}
  OutputDebugString(PChar(Format(FStrTab+'BeginSegment - FaceIndex %x', [AIndexFaceMap])));

  Inc(FLevelTab, 2);
  FStrTab := StringOfChar('.',FLevelTab);
{$ENDIF}
end;

procedure TsgCreatorEntityBase.EndSegment;
var
  I, J: Integer;
  vEntity, vEntitySpline: TsgDXFEntity;
  vLine: TsgDXFLine;
  vTempBlock: TsgDXFBlock;
  vLoad: Boolean;
{$IFDEF SG_BREP_DEBUG}
  vCount: Integer;
{$ENDIF}
{$IFDEF SG_BREP_TOPOLOGY}
  vFindBrepTopology: TsgBrepObjectTopology;
  vFindBrepTopologyFace: TsgBrepIndexFace;
  vFindBrepTopologyAcisFace: TsgDXFACISIndexFace;
  vTempInsert: TsgDXFInsert;
{$ENDIF}

  function IsBrepObject: Boolean;
  begin
    Result := (vEntity.ClassType = TsgBrepIndexFace) or
              (vEntity is TsgDXFACISIndexFace);
  end;
{$IFDEF SG_BREP_TOPOLOGY}
  procedure AddAttrib(AInsert: TsgDXFInsert; ATag, AText: string);
  var
    vAttrib: TsgDXFAttrib;
  begin
    vAttrib := TsgDXFAttrib.Create;
    AInsert.AddEntity(vAttrib);
    vAttrib.NotAppear := True;
    vAttrib.Tag := ATag;
    vAttrib.Text := AText;
    vAttrib.Value := vAttrib.Text;
    vAttrib.Point := FPointXMat(cnstFPointZero, AInsert.GetMatrix);
    vAttrib.Height := 1;
    FConverter.Loads(vAttrib);
  end;
{$ENDIF}
  function LenByFit(const AFit: TFPointList): Double;
  var
    I, vCount: Integer;
    vSegm: Double;
  begin
    vCount := AFit.Count;
    Result := 0;
    I := 1;
    while I < vCount  do
    begin
      vSegm := DistanceFPoint(AFit[I], AFit[I-1], 0);
      Result := Result + vSegm;
      Inc(I);
    end;
  end;

begin
  FCurrentFace := nil;

  vLoad := True;
  vTempBlock := FCurrentBlock;

{$IFDEF SG_BREP_TOPOLOGY}
  vTempInsert := FCurrentInsert;
{$ENDIF}

  if FStackBlock.Count <> 0 then
  begin
    FCurrentBlock := TsgDXFBlock(FStackBlock.Pop);
{$IFDEF SG_BREP_TOPOLOGY}
    FCurrentTopology := TsgBrepObjectTopology(FStackTopology.Pop);
    FCurrentInsert := TsgDXFInsert(FStackInsert.Pop);
{$ENDIF}
    if FCurrentBlock = vTempBlock then
    begin
      vLoad := False
    end
  end
  else
  begin
    FCurrentBlock := nil;
{$IFDEF SG_BREP_TOPOLOGY}
    FCurrentInsert := nil;
{$ENDIF}
  end;


{$IFDEF SG_BREP_DEBUG}
  vCount := 0;
{$ENDIF}

  if vLoad and (vTempBlock <> nil) then
  begin
    I := 0;
    while I < vTempBlock.Count do
    begin
      vEntity := vTempBlock[I];
      if IsBrepObject then
      begin
{$IFDEF SG_BREP_DEBUG}
        vCount := vEntity.Count;
{$ENDIF}
        if vEntity.Count = 0 then
        begin
          vTempBlock.DeleteEntity(I);
          vEntity.Free;
          Continue;
        end
        else
        begin
          // Loads
          J := 0;
          while J < vEntity.Count do
          begin
            FConverter.Loads(vEntity[J]);
            if (vEntity[J] is TsgDXFSpline) then
            begin
              if (LenByFit(TsgDXFSpline(vEntity[J]).Fit) < fDoubleResolution) then
              begin
                vEntitySpline := vEntity[J];
                vEntity.DeleteEntity(J);
                vLine := TsgDXFLIne(CreateEntityInternal(TsgDXFLine));
                vLine.Point := TsgDXFSpline(vEntitySpline).FitPoints[0];
                vLine.Point1 := vLine.Point;
                vEntity.InsertEntity(J, vLine);
                FConverter.Loads(vEntity[J]);
                vEntitySpline.Free;
              end;
            end;
            Inc(J);
          end;
        end;
      end;
      if vEntity is TsgDXFInsert then
      begin
        if TsgDXFInsert(vEntity).Block.Count = 0 then
        begin
         FConverter.Sections[csBlocks].RemoveEntity(TsgDXFInsert(vEntity).Block);
         TsgDXFInsert(vEntity).Block.Free;
         vTempBlock.DeleteEntity(I);
         vEntity.Free;
         Continue;
        end;

{$IFDEF SG_BREP_TOPOLOGY}
        if GlobalCalcTopogy = 1 then
        begin
          vFindBrepTopologyFace := nil;
          vFindBrepTopologyAcisFace := nil;
          for J := 0 to TsgDXFInsert(vEntity).Block.Count - 1 do
          begin
            if TsgDXFInsert(vEntity).Block.Entities[J] is TsgBrepIndexFace then
            begin
             vFindBrepTopologyFace := TsgBrepIndexFace(TsgDXFInsert(vEntity).Block.Entities[J]);
             Break;
            end;
            if TsgDXFInsert(vEntity).Block.Entities[J] is TsgDXFACISIndexFace then
            begin
             vFindBrepTopologyAcisFace := TsgDXFACISIndexFace(TsgDXFInsert(vEntity).Block.Entities[J]);
             Break;
            end;
          end;
          if Assigned(vFindBrepTopologyFace) then
            AddAttrib(TsgDXFInsert(vEntity), cnstBrepArea, DoubleToStr(vFindBrepTopologyFace.Area));
          if Assigned(vFindBrepTopologyAcisFace) then
            AddAttrib(TsgDXFInsert(vEntity), cnstBrepArea, DoubleToStr(vFindBrepTopologyAcisFace.Area));
        end;
{$ENDIF}
      end;
      FConverter.Loads(vEntity);
      Inc(I);
    end;
{$IFDEF SG_BREP_TOPOLOGY}
    if Assigned(vTempInsert) and (GlobalCalcTopogy = 1) then
    begin
      vFindBrepTopology := nil;
      for J := 0 to TsgDXFInsert(vTempInsert).Block.Count - 1 do
      begin
       if TsgDXFInsert(vTempInsert).Block.Entities[J] is TsgBrepObjectTopology then
       begin
         vFindBrepTopology := TsgBrepObjectTopology(TsgDXFInsert(vTempInsert).Block.Entities[J]);
         Break;
       end;
      end;
      if Assigned(vFindBrepTopology) then
      begin
        AddAttrib(vTempInsert, cnstBrepCenterMass, FPointToStr(vFindBrepTopology.CenterMass));
        if vFindBrepTopology.Volume > 0 then
          AddAttrib(vTempInsert, cnstBrepVolume, DoubleToStr(vFindBrepTopology.Volume));
        AddAttrib(vTempInsert, cnstBrepArea, DoubleToStr(vFindBrepTopology.Area));
        AddAttrib(vTempInsert, cnstBrepOriginalName, vFindBrepTopology.OriginalName);
      end;
    end;
{$ENDIF}
    FConverter.Loads(vTempBlock);
  end;

{$IFDEF SG_BREP_DEBUG}
  Dec(FLevelTab, 2);
  FStrTab := StringOfChar('.',FLevelTab);

  OutputDebugString(PChar(Format(FStrTab+'EndSegment - CountFaceEntyti %x - Count Entyti %x - ',
   [vCount, vTempBlock.Count])));
{$ENDIF}
end;

constructor TsgCreatorEntityBase.Create(const AConv: TsgDXFConverter;
  const ABase: TsgDXFEntity);
begin
  FCurrentBlock := nil;
  FCurrentFace := nil;
  FStackBlock := TsgStackObject.Create;
  FStackBlock.Clear;
{$IFDEF SG_BREP_TOPOLOGY}
  FStackTopology := TsgStackObject.Create;
  FStackTopology.Clear;
  FCurrentTopology := nil;

  FStackInsert := TsgStackObject.Create;
  FStackInsert.Clear;
  FCurrentInsert := nil;

{$ENDIF}
  FConverter := AConv;
  FBase := ABase;
{$IFDEF SG_BREP_DEBUG}
  OutputDebugString(PChar('ACIS Start ----'));
  FLevelTab := 2;
  FStrTab := StringOfChar('.',FLevelTab);
{$ENDIF}
{$IFDEF CHECK_TIME}
  IsCalcTick := False;
  TicksLoadOpenCascade := GetTickCount;
  OutputDebugString(PChar('Start Load file'));
{$ENDIF}
end;

function TsgCreatorEntityBase.CreateEntity(const AClass: TClass;
  const AFirstPoint, ALastPoint: PFPoint;
  var IsCreated: Boolean): TsgDXFEntity;
var
  vEnt: TsgDXFEntity;
  vFlatPoly3D: TsgFlatPoly3D;
  vSpline: TsgDXFSpline;
  vIndexLastEntity: Integer;
  vCurrentParent: TsgDXFEntity;
  vClass: TClass;

  function FindLastEntity(ACurrentEntity: TsgDXFEntity): Integer;
  var
    I: Integer;
    vEntFind: TsgDXFEntity;
  begin
    Result := -1;
    for I:= ACurrentEntity.Count-1 downto 0 do
    begin
      vEntFind := ACurrentEntity.Entities[I];
      case vEntFind.EntType of
        ceInsert: Continue;
      else
        Result := I;
        Break;
      end;
    end;
  end;

begin
  Result := nil;
  IsCreated := False;
  vCurrentParent := GetCurrentParent;
  if AClass = TsgPolyline3D then
    vClass := TsgDXFSpline
  else
    vClass := AClass;
  if (vCurrentParent.Count > 0) and (AFirstPoint <> nil)then
  begin
    vIndexLastEntity := FindLastEntity(vCurrentParent);
    if vIndexLastEntity <> -1 then
    begin
      vEnt := vCurrentParent.Entities[vIndexLastEntity];
      if vEnt.ClassType = vClass then
      begin
        case vEnt.EntType of
          ceFlatPoly3D:
            begin
              vFlatPoly3D := TsgFlatPoly3D(vEnt);
              if not IsEqualFPoints(vFlatPoly3D.XYLast , AFirstPoint^) then
                vFlatPoly3D.AddSegmentPoint(AFirstPoint^, True);
              vFlatPoly3D.AddSegmentPoint(ALastPoint^, False);
              Result := vFlatPoly3D;
            end;
          ceSpline:
            begin
              vSpline := TsgDXFSpline(vEnt);
              if IsEqualFPoints(vSpline.Fit.Last , AFirstPoint^) then
              begin
                TsgDXFSpline(vSpline).Fit.Add(ALastPoint^);
                TsgDXFSpline(vSpline).Fit.Add(ALastPoint^);
                Result := vSpline;
              end;
            end;
        end;
      end;
    end;
  end;
  if Result = nil then
  begin
    IsCreated := True;
    Result := CreateEntityInternal(vClass);
    case Result.EntType of
      ceFlatPoly3D:
        begin
          if (AFirstPoint <> nil) and (ALastPoint <> nil) then
          begin
            TsgFlatPoly3D(Result).AddSegmentPoint(AFirstPoint^, True);
            TsgFlatPoly3D(Result).AddSegmentPoint(ALastPoint^, False);
          end;
        end;
      ceSpline:
        begin
          if AClass = TsgPolyline3D then
            TsgDXFSplineAccess(Result).FlagsExtented := 1;
          if (AFirstPoint <> nil) and (ALastPoint <> nil) then
          begin
            TsgDXFSpline(Result).Fit.Add(AFirstPoint^);
            TsgDXFSpline(Result).Fit.Add(AFirstPoint^);
            TsgDXFSpline(Result).Fit.Add(ALastPoint^);
            TsgDXFSpline(Result).Fit.Add(ALastPoint^);
          end;
        end;
    end;
  end;
end;

function TsgCreatorEntityBase.CreateEntityInternal(
  const AClass: TClass): TsgDXFEntity;
begin
  Result := TsgDXFEntityClass(AClass).Create;
  if Result is TsgDXFInsert then
    TsgDXFInsertAccess(Result).SceneElement := 1;
  TsgDXFEntityAccess(Result).SetConverter(FConverter);
  Result.LineTypeScale := FBase.LineTypeScale;

  if GetCurrentParent = FBase then
    Result.ColorCAD := FBase.ColorCAD
  else
  begin
      Result.ColorCAD := cnstColorCADByBlock;
  end;
  Result.LineType := FBase.LineType;
  Result.Layer := FBase.Layer;
end;

function TsgCreatorEntityBase.CreateIndexFace(AIndexFace: Integer): TsgBrepEntity;
begin
    Result := TsgBrepEntity(TsgBrepIndexFace.Create);
    TsgBrepIndexFace(Result).AssignEntity(FBase);
    TsgBrepIndexFace(Result).ColorCAD := cnstColorCADByBlock;
    TsgBrepIndexFace(Result).Owner := TsgBrepGroup(FBase);
    TsgBrepIndexFace(Result).IndexFaceMap := AIndexFace;
{$IFDEF SG_BREP_TOPOLOGY}
    TsgBrepIndexFace(Result).ReferenceToTopology := FCurrentTopology;
{$ENDIF}
end;

{$IFDEF SG_BREP_TOPOLOGY}
function TsgCreatorEntityBase.CreateObjectTopology(ACenterMass: TFPoint;
      AVolume, AArea: Double; AName: string): TsgBrepEntity;
begin
    Result := TsgBrepEntity(TsgBrepObjectTopology.Create);
    TsgBrepObjectTopology(Result).AssignEntity(FBase);
    TsgBrepObjectTopology(Result).ColorCAD := cnstColorCADByBlock;
    TsgBrepObjectTopology(Result).Owner := TsgBrepGroup(FBase);
    TsgBrepObjectTopology(Result).CenterMass := ACenterMass;
    TsgBrepObjectTopology(Result).OriginalName := AName;
    TsgBrepObjectTopology(Result).Volume := AVolume;
    TsgBrepObjectTopology(Result).Area := AArea;
end;

procedure TsgCreatorEntityBase.SetObjectTopologyFace(AArea: Double);
begin
  if Assigned(FCurrentFace) then
  begin
    TsgBrepIndexFace(FCurrentFace).Area := AArea;
  end;
end;
{$ENDIF}

destructor TsgCreatorEntityBase.Destroy;
begin

{$IFDEF CHECK_TIME}
   if not IsCalcTick then
     OutputDebugString(PChar(Format('All loading time is %s mlsek',
      [FloatToStr(GetTickCount - TicksLoadOpenCascade)])))
   else
     OutputDebugString(PChar(Format('Loading time is %s mlsek',
    [FloatToStr(GetTickCount - TicksLoad)])));
{$ENDIF}

{$IFDEF SG_BREP_DEBUG}
  OutputDebugString(PChar('ACIS End ----'));
{$ENDIF}
  FStackBlock.Clear;
  FStackBlock.Free;
{$IFDEF SG_BREP_TOPOLOGY}
  FStackTopology.Clear;
  FStackTopology.Free;
  FStackInsert.Clear;
  FStackInsert.Free;
{$ENDIF}
  inherited;
end;

{ TsgBrepCreateEntity }

function TsgSatCreatorEntity.AddEntityInternal(const AEntity: TsgDXFEntity): TsgDXFEntity;
begin
  FOwner.SetCoEdgeReversed(AEntity);
  Result := inherited AddEntityInternal(AEntity);
end;

constructor TsgSatCreatorEntity.CreateEx(const AOwner: TsgSATParser;
  const ABase: TsgDXFEntity);
begin
  FOwner := AOwner;
  Create(FOwner.FConverter, ABase);
end;

function TsgSatCreatorEntity.CreateIndexFace(AIndexFace: Integer): TsgBrepEntity;
begin
    Result := TsgBrepEntity(TsgDXFACISIndexFace.Create);
    TsgDXFACISIndexFace(Result).AssignEntity(FBase);
    TsgDXFACISIndexFace(Result).ColorCAD := cnstColorCADByBlock;
    TsgDXFACISIndexFace(Result).Owner := TsgDXFACISEntity(FBase);
    TsgDXFACISIndexFace(Result).IndexFaceMap := AIndexFace;
end;

{$IFDEF SG_BREP_TOPOLOGY}
procedure TsgSatCreatorEntity.SetObjectTopologyFace(AArea: Double);
begin
  if Assigned(FCurrentFace) then
  begin
    TsgDXFACISIndexFace(FCurrentFace).Area := AArea;
  end;
end;
{$ENDIF}

procedure BeginSegment(Param: Pointer; IndexFaceMap: Integer;
  SegmentData: PsgSegmentData); cdecl;
var
  vCreator: TsgCreatorEntityBase;
  vParams: PsgParamTriangle;
  vRed, vGreen, vBlue: Byte;
  vName: string;
{$IFDEF SG_BREP_TOPOLOGY}
  vBrepObjectTopology: TsgBrepEntity;
  vVolume, vArea: Double;
  vCenterMass: TFPoint;
{$ENDIF}
begin
  vParams := PsgParamTriangle(Param);
  vCreator := TsgCreatorEntityBase(vParams^.ASelf);

  if (SegmentData <> nil) and (SegmentData.NameDataBoundedByZero <> nil) then
    vName := string(PAnsiChar(SegmentData.NameDataBoundedByZero))
  else
    vName := '';

{$IFDEF SG_BREP_TOPOLOGY}
  if (SegmentData <> nil) and (SegmentData.ExtData > 0) then
    begin
      case IndexFaceMap of
        -3:
          begin
            vVolume := SegmentData.Volume;
            vArea := SegmentData.Area;
            vCenterMass := MakeFPoint(SegmentData.CenterMass.X,
              SegmentData.CenterMass.Y, SegmentData.CenterMass.Z);
            // Level object topology
            vBrepObjectTopology := TsgBrepEntity( vCreator.CreateObjectTopology(vCenterMass,
              vVolume, vArea, vName));
            TsgBrepObjectTopology(vBrepObjectTopology).ReferenceToContainer :=
              vCreator.AddEntity(vBrepObjectTopology);
          end;
        -4:
          begin
            vArea := SegmentData.Area;
            vCreator.SetObjectTopologyFace(vArea);
          end;
      end;
    end
  else
{$ENDIF}
    if (SegmentData = nil) or (SegmentData.FoundColor = 0) then
      vCreator.BeginSegment(cnstColorCADByBlock, IndexFaceMap, vName)
    else
    begin
      vRed := Trunc(SegmentData.Red*255);
      vGreen := Trunc(SegmentData.Green*255);
      vBlue := Trunc(SegmentData.Blue*255);
      vCreator.BeginSegment(
        ConvertColorToColorCAD(ConvertRGBtoColor(vRed, vGreen, vBlue)),
        IndexFaceMap, vName);
    end;
end;

procedure EndSegment(Param: Pointer); cdecl;
var
  vCreator: TsgCreatorEntityBase;
  vParams: PsgParamTriangle;
begin
  vParams := PsgParamTriangle(Param);
  vCreator := TsgCreatorEntityBase(vParams^.ASelf);
  vCreator.EndSegment;
end;

procedure GetTriangle(DimTriangle: PsgDimTriangle; Param: Pointer); cdecl;
var
  vCreator: TsgDXFEntity;

  I: Integer;
  vTriangle: PsgTriangle;
  vPointer: Pointer;
  vParams: PsgParamTriangle;
  vPoint1, vPoint2, vPoint3: TFPoint;
  vFace: TsgDXF3dFace;

begin
  vParams := PsgParamTriangle(Param);
  vCreator := TsgDXFEntity(vParams^.ASelf);
  vPointer := Pointer(TsgNativePointer(DimTriangle) + TsgNativePointer(SizeOf(Integer)));
  for I := 0 to DimTriangle^.CountTriangle - 1 do
  begin
    vTriangle := Pointer(TsgNativePointer(vPointer) + TsgNativePointer(SizeOf(TsgTriangle)*I));
    vPoint1 := MakeFPoint(vTriangle^.Corner1.X, vTriangle^.Corner1.Y,
      vTriangle^.Corner1.Z);
    vPoint2 := MakeFPoint(vTriangle^.Corner2.X, vTriangle^.Corner2.Y,
      vTriangle^.Corner2.Z);
    vPoint3 := MakeFPoint(vTriangle^.Corner3.X, vTriangle^.Corner3.Y,
      vTriangle^.Corner3.Z);
    vFace := TsgDXF3dFace.Create;
    vFace.Flags := $F;
    vFace.Point := vPoint1;
    vFace.Point1 := vPoint2;
    vFace.Point2 := vPoint3;
    vFace.Point3 := vFace.Point2;
    vFace.ColorCAD := cnstColorCADByBlock;
    vFace.LineType := vCreator.LineType;
    vFace.Layer := vCreator.Layer;
    vCreator.AddEntity(vFace);
  end;
end;

procedure CallBackVertexDraw(AData: PsgTestLine; const AClass: TClass);
const
  cnstBadCan = 9000000000;
var
  vCreator: TsgCreatorEntityBase;
  vEntity: TsgDXFEntity;
  vPoint1, vPoint2: TFPoint;
  vIsCreated: Boolean;

  function isBadPoint(APoint: TFPoint): Boolean;
  begin
    Result := IsNan(APoint.X) or IsInfinite(APoint.X);
    Result := Result or IsNan(APoint.Y) or IsInfinite(APoint.Y);
    Result := Result or IsNan(APoint.Z) or IsInfinite(APoint.Z);
  end;

begin
  vPoint1 := MakeFPoint(AData.Point1.X, AData.Point1.Y, AData.Point1.Z);
  vPoint2 := MakeFPoint(AData.Point2.X, AData.Point2.Y, AData.Point2.Z);
  if isBadPoint(vPoint1) or isBadPoint(vPoint2) then
    Exit;
  if IsRangeFPoints(vPoint1, cnstFPointZero, MakeFPoint(cnstBadCan, cnstBadCan, cnstBadCan)) or
    IsRangeFPoints(vPoint2, cnstFPointZero, MakeFPoint(cnstBadCan, cnstBadCan, cnstBadCan)) then
  begin
    vCreator := TsgCreatorEntityBase(AData.Creator);
    vEntity := vCreator.CreateEntity(AClass, @vPoint1, @vPoint2, vIsCreated);
    if vIsCreated then
      vCreator.AddEntity(vEntity);
  end;
end;

procedure CallBackDrawWireVertexDraw(AData: PsgTestLine); cdecl;
begin
  CallBackVertexDraw(AData, TsgFlatPoly3D);
end;

procedure CallBackDrawISOVertexDraw(AData: PsgTestLine); cdecl;
begin
  CallBackVertexDraw(AData, TsgPolyline3D);
end;

procedure CallBackDrawTestVertexDraw(AData: PsgTestLine); cdecl;
begin
  CallBackVertexDraw(AData, TsgFlatPoly3D);
end;


initialization
  GlobalMultithreading := 0;
{$IFDEF SG_BREP_TOPOLOGY}
  GlobalCalcTopogy := 1;
{$ENDIF}

end.
