{************************************************************}
{                   Delphi VCL Extensions                    }
{                                                            }
{                TsgIteratorBase class                       }
{                                                            }
{      Copyright (c) 2002-2013 SoftGold software company     }
{                                                            }
{************************************************************}

unit sgIterator;

interface

uses
  DXFConv, sgConsts, sgFunction;

const
  cnstContinueIterate = 1;

type
  TsgIteratorProc = class
  private
    FOwner: TObject;
    function GetIterateParams: PsgCADIterate;
    function GetConverter: TsgDXFConverter;
  public
    function BeginProc(Entity: TsgDXFEntity): Integer; virtual;
    function FinishProc(Entity: TsgDXFEntity): Integer; virtual;
    function GetPoint(const APoint: TFPoint): TFPoint;
    property IterateParams: PsgCADIterate read GetIterateParams;
    property Converter: TsgDXFConverter read GetConverter;
  end;

  TsgRotateImage = class(TsgIteratorProc)
  protected
    function DoImageEnt(const AImageEnt: TsgDXFImageEnt): Integer;
  public
    function BeginProc(Entity: TsgDXFEntity): Integer; override;
  end;

  TsgIteratorBase = class
  private
    FDrawParams: PsgCADIterate;
    FConverter: TsgDXFConverter;
    FIterateParams: TsgCADIterate;
    FIterateProc: TsgIteratorProc;
    function GetIterateParams: PsgCADIterate;
  protected
    procedure AfterIterate(const ACadImage: TObject); virtual;
    procedure BeforeIterate(const ACadImage: TObject); virtual;
    function BeginProc(Entity: TsgDXFEntity): Integer;
    function FinishProc(Entity: TsgDXFEntity): Integer;
    function GetViewMatrix: TFMatrix; virtual;
    procedure LayoutIterate(const AConverter, ALayout: TObject);
    property Converter: TsgDXFConverter read FConverter;
    property IterateParams: PsgCADIterate read GetIterateParams;
  public
    constructor Create(const AProc: TsgIteratorProc); virtual;
    destructor Destroy; override;
    function Iterate(const ACadImage: TObject): Boolean;
  end;

implementation

uses
  CADImage;

type
   TsgCADImageAccess = class(TsgCADImage);
   TsgDXFImageEntAccess = class(TsgDXFImageEnt);

{ TsgIteratorBase }

function TsgIteratorBase.BeginProc(Entity: TsgDXFEntity): Integer;
begin
  Result := cnstContinueIterate;
  if FIterateProc <> nil then
    Result := FIterateProc.BeginProc(Entity);
end;

constructor TsgIteratorBase.Create(const AProc: TsgIteratorProc);
begin
  inherited Create;
  FIterateProc := AProc;
  if FIterateProc <> nil then
    FIterateProc.FOwner := Self;
end;

destructor TsgIteratorBase.Destroy;
begin
  inherited Destroy;
end;

function TsgIteratorBase.FinishProc(Entity: TsgDXFEntity): Integer;
begin
  Result := cnstContinueIterate;
end;

function TsgIteratorBase.GetIterateParams: PsgCADIterate;
begin
  Result := @FIterateParams;
end;

function TsgIteratorBase.GetViewMatrix: TFMatrix;
begin
  Result := cnstCrossYMat;
end;

function TsgIteratorBase.Iterate(const ACadImage: TObject): Boolean;
var
  vCADImage: TsgCADImageAccess absolute ACadImage;
  I: Integer;
begin
  Result := (ACadImage is TsgCADImage) and (FIterateProc <> nil);
  if Result then
  begin
    BeforeIterate(ACadImage);
    try
      for I := 0 to vCADImage.LayoutsCount - 1 do
      begin
        FillChar(FIterateParams, SizeOf(FIterateParams), 0);
        FIterateParams.Matrix := FMatXMat(vCADImage.GetRealImageMatrix, GetViewMatrix);
        FIterateParams.Additional := Integer(IsRotatedFMat(FIterateParams.Matrix));
        LayoutIterate(vCADImage.Converter, vCADImage.Layouts[I]);
      end;
    finally
      AfterIterate(ACadImage);
    end;
  end;
end;

procedure TsgIteratorBase.LayoutIterate(const AConverter, ALayout: TObject);
var
  vLauout: TsgDXFLayout absolute ALayout;
begin
  vLauout.Iterate(TsgDXFConverter(AConverter), BeginProc, FinishProc);
end;

procedure TsgIteratorBase.AfterIterate(const ACadImage: TObject);
var
  vCADImage: TsgCADImageAccess absolute ACadImage;
begin
  vCADImage.Converter.Params := FDrawParams;
  FConverter := nil;
end;

procedure TsgIteratorBase.BeforeIterate(const ACadImage: TObject);
var
  vCADImage: TsgCADImageAccess absolute ACadImage;
begin
  FDrawParams := vCADImage.Converter.Params;
  FConverter := vCADImage.Converter;
  vCADImage.Converter.Params := @FIterateParams;
end;

{ TsgIteratorProc }

function TsgIteratorProc.BeginProc(Entity: TsgDXFEntity): Integer;
begin
  Result := cnstContinueIterate;
end;

function TsgIteratorProc.FinishProc(Entity: TsgDXFEntity): Integer;
begin
  Result := cnstContinueIterate;
end;

function TsgIteratorProc.GetConverter: TsgDXFConverter;
begin
  if FOwner <> nil then
    Result := TsgIteratorBase(FOwner).Converter
  else
    Result := nil;
end;

function TsgIteratorProc.GetIterateParams: PsgCADIterate;
begin
  if FOwner <> nil then
    Result := TsgIteratorBase(FOwner).IterateParams
  else
    Result := nil;
end;

function TsgIteratorProc.GetPoint(const APoint: TFPoint): TFPoint;
begin
  Result := FPointXMat(APoint, IterateParams^.Matrix);
end;

{ TsgRotateImage }

function TsgRotateImage.BeginProc(Entity: TsgDXFEntity): Integer;
begin
  if Entity.EntType = ceImageEnt then
    Result := DoImageEnt(TsgDXFImageEnt(Entity))
  else
    Result := inherited BeginProc(Entity);
end;

function TsgRotateImage.DoImageEnt(const AImageEnt: TsgDXFImageEnt): Integer;
var
  vAngleX, vAngleY: Double;
begin
  Result := cnstContinueIterate;
  vAngleX := GetAngleByPoints(GetPoint(AImageEnt.Point),
    GetPoint(AImageEnt.Point1), False, fDoubleResolution ,1, -1);
  vAngleY :=  GetAngleByPoints(GetPoint(AImageEnt.Point),
    GetPoint(AImageEnt.Point2), False, fDoubleResolution, 1, -1);
  if not IsDrawGDI(vAngleX, vAngleY) then
  begin
    if IsEqual((Round(vAngleX) div 90) * 90, vAngleX) then
      TsgDXFImageEntAccess(AImageEnt).DoRotate(360-vAngleX, Converter);
  end;
end;

end.
