//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.4 (Public License)
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
//
// Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3)
// Pascal Port By: Milan Marusinec alias Milano
//                 milan@marusinec.sk
//                 http://www.aggpas.org
// Copyright (c) 2005-2006
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
//          mcseemagg@yahoo.com
//          http://www.antigrain.com
//
//----------------------------------------------------------------------------
//
// Bilinear 2D transformations
//
// [Pascal Port History] -----------------------------------------------------
//
// 23.06.2006-Milano: ptrcomp adjustments
// 07.02.2006-Milano: Unit port establishment
//
{ agg_trans_bilinear.pas }
unit
 agg_trans_bilinear ;

INTERFACE

{$I agg_mode.inc }

uses
 agg_basics ,
 agg_trans_affine ,
 agg_simul_eq ;

{ TYPES DEFINITION }
type
 iterator_x = object
   inc_x ,inc_y ,x ,y : double;

   constructor Construct; overload;
   constructor Construct(tx ,ty ,step : double; m : double_42_ptr ); overload;

   procedure inc_operator;

  end;

 trans_bilinear_ptr = ^trans_bilinear;
 trans_bilinear = object(trans_affine )
   m_valid : boolean;
   m_mtx   : array[0..3 ,0..1 ] of double;

   constructor Construct; overload;

  // Arbitrary quadrangle transformations
   constructor Construct(src ,dst : double_ptr ); overload;

  // Direct transformations
   constructor Construct(x1 ,y1 ,x2 ,y2 : double; quad : double_ptr ); overload;

  // Reverse transformations
   constructor Construct(quad : double_ptr; x1 ,y1 ,x2 ,y2 : double ); overload;

  // Set the transformations using two arbitrary quadrangles.
   procedure quad_to_quad(src ,dst : double_ptr );

  // Set the direct transformations, i.e., rectangle -> quadrangle
   procedure rect_to_quad(x1 ,y1 ,x2 ,y2 : double; quad : double_ptr );

  // Set the reverse transformations, i.e., quadrangle -> rectangle
   procedure quad_to_rect(quad : double_ptr; x1 ,y1 ,x2 ,y2 : double );

  // Check if the equations were solved successfully
   function  is_valid : boolean;

   function  begin_(x ,y ,step : double ) : iterator_x;

  end;

{ GLOBAL PROCEDURES }


IMPLEMENTATION
{ LOCAL VARIABLES & CONSTANTS }
{ UNIT IMPLEMENTATION }
{ CONSTRUCT }
constructor iterator_x.Construct;
begin
end;

{ CONSTRUCT }
constructor iterator_x.Construct(tx ,ty ,step : double; m : double_42_ptr );
begin
 inc_x:=m^[1 ,0 ] * step * ty + m^[2 ,0 ] * step;
 inc_y:=m^[1 ,1 ] * step * ty + m^[2 ,1 ] * step;

 x:=m^[0 ,0 ] + m^[1 ,0 ] * tx * ty + m^[2 ,0 ] * tx + m^[3 ,0 ] * ty;
 y:=m^[0 ,1 ] + m^[1 ,1 ] * tx * ty + m^[2 ,1 ] * tx + m^[3 ,1 ] * ty;

end;

{ INC_OPERATOR }
procedure iterator_x.inc_operator;
begin
 x:=x + inc_x;
 y:=y + inc_y;

end;

{ _transform }
procedure _transform(this : trans_bilinear_ptr; x ,y : double_ptr );
var
 tx ,ty ,xy : double;

begin
 tx:=x^;
 ty:=y^;
 xy:=tx * ty;

 x^:=this.m_mtx[0 ,0 ] + this.m_mtx[1 ,0 ] * xy + this.m_mtx[2 ,0 ] * tx + this.m_mtx[3 ,0 ] * ty;
 y^:=this.m_mtx[0 ,1 ] + this.m_mtx[1 ,1 ] * xy + this.m_mtx[2 ,1 ] * tx + this.m_mtx[3 ,1 ] * ty;

end;

{ CONSTRUCT }
constructor trans_bilinear.Construct;
begin
 inherited Construct;

 m_valid:=false;

 transform:=@_transform;

end;

{ CONSTRUCT }
constructor trans_bilinear.Construct(src ,dst : double_ptr );
begin
 inherited Construct;

 quad_to_quad(src ,dst );

 transform:=@_transform;

end;

{ CONSTRUCT }
constructor trans_bilinear.Construct(x1 ,y1 ,x2 ,y2 : double; quad : double_ptr );
begin
 inherited Construct;

 rect_to_quad(x1 ,y1 ,x2 ,y2 ,quad );

 transform:=@_transform;

end;

{ CONSTRUCT }
constructor trans_bilinear.Construct(quad : double_ptr; x1 ,y1 ,x2 ,y2 : double );
begin
 inherited Construct;

 quad_to_rect(quad ,x1 ,y1 ,x2 ,y2 );

 transform:=@_transform;

end;

{ QUAD_TO_QUAD }
procedure trans_bilinear.quad_to_quad;
var
 left  : double_44;
 right : double_42;

 i ,ix ,iy : unsigned;

begin
 for i:=0 to 3 do
  begin
   ix:=i * 2;
   iy:=ix + 1;

   left[i ,0 ]:=1.0;
   left[i ,1 ]:=double_ptr(ptrcomp(src ) + ix * sizeof(double ) )^ * double_ptr(ptrcomp(src ) + iy * sizeof(double ) )^;
   left[i ,2 ]:=double_ptr(ptrcomp(src ) + ix * sizeof(double ) )^;
   left[i ,3 ]:=double_ptr(ptrcomp(src ) + iy * sizeof(double ) )^;

   right[i ,0 ]:=double_ptr(ptrcomp(dst ) + ix * sizeof(double ) )^;
   right[i ,1 ]:=double_ptr(ptrcomp(dst ) + iy * sizeof(double ) )^;

  end;

 m_valid:=simul_eq_solve(@left ,@right ,@m_mtx ,4 ,2 );

end;

{ RECT_TO_QUAD }
procedure trans_bilinear.rect_to_quad;
var
 src : double_8;

begin
 src[0 ]:=x1;
 src[6 ]:=x1;
 src[2 ]:=x2;
 src[4 ]:=x2;
 src[1 ]:=y1;
 src[3 ]:=y1;
 src[5 ]:=y2;
 src[7 ]:=y2;

 quad_to_quad(@src ,quad );

end;

{ QUAD_TO_RECT }
procedure trans_bilinear.quad_to_rect;
var
 dst : double_8;

begin
 dst[0 ]:=x1;
 dst[6 ]:=x1;
 dst[2 ]:=x2;
 dst[4 ]:=x2;
 dst[1 ]:=y1;
 dst[3 ]:=y1;
 dst[5 ]:=y2;
 dst[7 ]:=y2;

 quad_to_quad(quad ,@dst );

end;

{ IS_VALID }
function trans_bilinear.is_valid;
begin
 result:=m_valid;

end;

{ BEGIN_ }
function trans_bilinear.begin_;
begin
 result.Construct(x ,y ,step ,@m_mtx );

end;

END.