2017-11-23 02:41:34 +08:00
namespace UglyToad.Pdf.Core
{
using System ;
using Geometry ;
/// <summary>
/// Specifies the conversion from the transformed coordinate space to the original untransformed coordinate space.
/// </summary>
internal struct TransformationMatrix
{
2017-11-30 06:55:53 +08:00
public static TransformationMatrix Identity = new TransformationMatrix ( new decimal [ ]
2017-11-23 02:41:34 +08:00
{
1 , 0 , 0 ,
0 , 1 , 0 ,
0 , 0 , 1
} ) ;
private readonly decimal [ ] value ;
public decimal A = > value [ 0 ] ;
public decimal B = > value [ 1 ] ;
public decimal C = > value [ 3 ] ;
public decimal D = > value [ 4 ] ;
public decimal E = > value [ 6 ] ;
public decimal F = > value [ 7 ] ;
2017-11-30 06:55:53 +08:00
public decimal this [ int row , int col ]
{
get
{
if ( row > = Rows )
{
throw new ArgumentOutOfRangeException ( $"The transformation matrix only contains {Rows} rows and is zero indexed, you tried to access row {row}." ) ;
}
if ( row < 0 )
{
throw new ArgumentOutOfRangeException ( "Cannot access negative rows in a matrix." ) ;
}
if ( col > = Columns )
{
throw new ArgumentOutOfRangeException ( $"The transformation matrix only contains {Columns} columns and is zero indexed, you tried to access column {col}." ) ;
}
if ( col < 0 )
{
throw new ArgumentOutOfRangeException ( "Cannot access negative columns in a matrix." ) ;
}
var resultIndex = row * Rows + col ;
if ( resultIndex > value . Length - 1 )
{
throw new ArgumentOutOfRangeException ( $"Trying to access {row}, {col} mapped to the index {resultIndex} which was not in the value array." ) ;
}
return value [ resultIndex ] ;
}
}
public const int Rows = 3 ;
public const int Columns = 3 ;
2017-11-23 02:41:34 +08:00
public TransformationMatrix ( decimal [ ] value )
{
if ( value = = null )
{
throw new ArgumentNullException ( nameof ( value ) ) ;
}
if ( value . Length ! = 9 )
{
throw new ArgumentException ( "The constructor for the PDF transformation matrix must contain 9 elements. Instead got: " + value ) ;
}
this . value = value ;
}
public PdfPoint Transform ( PdfPoint original )
{
var x = A * original . X + C * original . Y + E ;
var y = B * original . X + D * original . Y + F ;
return new PdfPoint ( x , y ) ;
}
2017-12-01 07:34:38 +08:00
public static TransformationMatrix FromValues ( decimal a , decimal b , decimal c , decimal d , decimal e , decimal f )
= > FromArray ( new [ ] { a , b , c , d , e , f } ) ;
public static TransformationMatrix FromArray ( decimal [ ] values )
2017-11-23 02:41:34 +08:00
{
if ( values . Length = = 9 )
{
return new TransformationMatrix ( values ) ;
}
if ( values . Length = = 6 )
{
return new TransformationMatrix ( new [ ]
{
values [ 0 ] , values [ 1 ] , 0 ,
values [ 2 ] , values [ 3 ] , 0 ,
values [ 4 ] , values [ 5 ] , 1
} ) ;
}
throw new ArgumentException ( "The array must either define all 9 elements of the matrix or all 6 key elements. Instead array was: " + values ) ;
}
2017-11-30 06:55:53 +08:00
public TransformationMatrix Multiply ( TransformationMatrix matrix )
{
var result = new decimal [ 9 ] ;
for ( int i = 0 ; i < Rows ; i + + )
{
for ( int j = 0 ; j < Columns ; j + + )
{
var index = ( i * Rows ) + j ;
for ( int x = 0 ; x < Rows ; x + + )
{
result [ index ] + = this [ i , x ] * matrix [ x , j ] ;
}
}
}
return new TransformationMatrix ( result ) ;
}
public override bool Equals ( object obj )
{
if ( ! ( obj is TransformationMatrix m ) )
{
return false ;
}
return Equals ( this , m ) ;
}
public static bool Equals ( TransformationMatrix a , TransformationMatrix b )
{
for ( int i = 0 ; i < Rows ; i + + )
{
for ( int j = 0 ; j < Columns ; j + + )
{
if ( a [ i , j ] ! = b [ i , j ] )
{
return false ;
}
}
}
return true ;
}
2017-11-23 02:41:34 +08:00
public override string ToString ( )
{
return $"{A}, {B}, 0\r\n{C}, {D}, 0\r\n{E}, {F}, 1" ;
}
}
}